1
/* Copyright (C) 1995 Bjoern Beutel. */
3
/* Description. =============================================================*/
5
/* In this file, the administration of breakpoints is managed. */
7
/* Includes. ================================================================*/
18
#include "rule_type.h"
22
#include "breakpoints.h"
24
/* Types. ===================================================================*/
26
typedef struct /* Definition of a breakpoint. */
29
int_t number; /* Breakpoint number. */
30
rule_sys_t *rule_sys; /* Rule system of breakpoint. */
31
int_t instr; /* Instruction to break at. */
34
/* Variables. ===============================================================*/
36
static int_t breakpoint_count; /* Number of breakpoints so far. */
37
static list_t breakpoints; /* List of breakpoints. */
39
static int_t rule_system_count; /* Number of loaded rule systems. */
40
static rule_sys_name_t *rule_systems; /* Name for each rule system. */
42
/* Functions. ===============================================================*/
45
instruction_at( rule_sys_t *rule_sys, string_t file, int_t line )
46
/* Return the index of the first instruction at RULE_SYS, FILE, LINE
47
* or -1 if there is no code there. */
51
for (src_line = rule_sys->src_lines;
52
src_line < rule_sys->src_lines + rule_sys->src_line_count;
55
if (src_line->file != -1
56
&& strcmp( rule_sys->strings + src_line->file, file ) == 0
57
&& src_line->line >= line)
59
return src_line->instr;
65
/*---------------------------------------------------------------------------*/
68
find_rule_by_name( rule_sys_t *rule_sys, string_t rule_name )
69
/* Find the first line of rule RULE_NAME in RULE_SYS.
70
* Return the first instruction of this rule. */
74
for (i = 0; i < rule_sys->rule_count; i++)
76
if (strcmp_no_case( rule_sys->strings + rule_sys->rules[i].name,
79
return rule_sys->rules[i].first_instr;
85
/*---------------------------------------------------------------------------*/
88
complete_file_name( rule_sys_t *rule_sys, string_t file_name )
89
/* Return FILE_NAME completed if it is in RULE_SYS, else return NULL. */
93
for (src_line = rule_sys->src_lines;
94
src_line < rule_sys->src_lines + rule_sys->src_line_count;
97
if (src_line->file != -1
98
&& strcmp( name_in_path( rule_sys->strings + src_line->file ),
101
return rule_sys->strings + src_line->file;
107
/*---------------------------------------------------------------------------*/
110
parse_breakpoint( string_t arguments,
111
rule_sys_t **rule_sys,
114
/* Parse a breakpoint specification; ARGUMENTS must be
117
* "[RULE_SYS_NAME] [FILE LINE_NUMBER | RULE_NAME]".
118
* Set RULE_SYS, FILE and LINE according to it. */
132
*rule_sys = executed_rule_sys;
133
source_of_instr( executed_rule_sys, pc, line, file, NULL );
135
if (IS_DIGIT( *arguments ))
136
*line = parse_int( &arguments );
137
else if (*arguments != EOS) /* Read file name or rule name. */
139
argument = parse_word( &arguments );
141
/* See if ARGUMENT is a rule system name. */
142
for (i = 0; i < rule_system_count; i++)
144
if (rule_systems[i].rule_sys != NULL
145
&& strcmp_no_case( argument, rule_systems[i].name ) == 0)
147
*rule_sys = rule_systems[i].rule_sys;
148
free_mem( &argument );
149
argument = parse_word( &arguments );
154
/* If a line number follows, we have a file name. */
155
if (IS_DIGIT( *arguments ))
157
*line = parse_int( &arguments );
158
if (*rule_sys != NULL)
159
*file = complete_file_name( *rule_sys, argument );
162
for (i = 0; i < rule_system_count; i++)
164
if (rule_systems[i].rule_sys != NULL)
166
*rule_sys = rule_systems[i].rule_sys;
167
*file = complete_file_name( *rule_sys, argument );
174
complain( "No source file \"%s\".", argument );
176
else /* ARGUMENT should be a rule name. */
178
if (*rule_sys != NULL)
179
first_instr = find_rule_by_name( *rule_sys, argument );
182
first_instr = -1; /* Prevent a "not initialized" warning. */
183
for (i = 0; i < rule_system_count; i++)
185
if (rule_systems[i].rule_sys != NULL)
187
*rule_sys = rule_systems[i].rule_sys;
188
first_instr = find_rule_by_name( *rule_sys, argument );
189
if (first_instr != -1)
194
if (first_instr == -1)
195
complain( "Rule \"%s\" is unknown.", argument );
197
/* Find the corresponding source line. */
198
source_of_instr( *rule_sys, first_instr, line, file, NULL );
200
free_mem( &argument );
202
parse_end( &arguments );
205
complain( "Missing file name." );
207
complain( "Missing line number." );
210
/*---------------------------------------------------------------------------*/
213
at_breakpoint( rule_sys_t *rule_sys, int_t instr )
214
/* Return breakpoint number if INSTR in RULE_SYS hits a
215
* breakpoint; return 0 else. */
219
FOREACH( bp, breakpoints )
221
if (bp->rule_sys == rule_sys && bp->instr == instr)
227
/*---------------------------------------------------------------------------*/
230
delete_all_breakpoints( void )
231
/* Run through breakpoint list and free all breakpoints. */
233
while (breakpoints.first != NULL)
234
free_first_node( &breakpoints );
237
/*---------------------------------------------------------------------------*/
240
do_delete( string_t argument )
241
/* Remove a breakpoint. */
245
breakpoint_t *breakpoint;
247
if (IS_ALPHA( *argument ))
249
word = parse_word( &argument );
250
if (strcmp_no_case( word, "all" ) != 0)
251
complain( "\"all\" or breakpoint numbers expected, not \"%s\".", word );
252
delete_all_breakpoints();
256
while (*argument != EOS)
258
break_num = parse_int( &argument );
260
/* Delete breakpoint with BREAK_NUM. */
261
FOREACH( breakpoint, breakpoints )
263
if (breakpoint->number == break_num)
266
if (breakpoint == NULL)
267
complain( "No breakpoint %d.", break_num );
268
free_node( &breakpoints, (list_node_t *) breakpoint );
271
parse_end( &argument );
274
command_t delete_command =
276
"delete d", do_delete,
277
"Delete breakpoints.\n"
279
" delete NUMBER ... -- Delete specified breakpoints.\n"
280
" delete all -- Delete all breakpoints.\n"
283
/*---------------------------------------------------------------------------*/
286
get_breakpoint( string_t argument,
287
rule_sys_t **rule_sys_p, int_t *instr_p )
288
/* Parse a breakpoint in ARGUMENT and set the remaining arguments. */
293
/* Parse breakpoint ARGUMENT. */
294
parse_breakpoint( argument, rule_sys_p, &file, &line );
296
/* Find first instruction of this breakpoint */
297
*instr_p = instruction_at( *rule_sys_p, file, line );
299
complain( "No code at file \"%s\", line %d.", name_in_path( file ), line );
302
/*---------------------------------------------------------------------------*/
305
do_break( string_t argument )
306
/* Define a breakpoint. */
308
rule_sys_t *rule_sys;
311
breakpoint_t *breakpoint;
313
/* Parse breakpoint ARGUMENT. */
314
get_breakpoint( argument, &rule_sys, &instr );
316
/* Check if other breakpoints exist at this position. */
317
FOREACH( breakpoint, breakpoints )
319
if (breakpoint->rule_sys == rule_sys && breakpoint->instr == instr)
320
complain( "Breakpoint %d already set here.", breakpoint->number );
323
/* Add breakpoint. */
324
breakpoint = new_node( &breakpoints, sizeof( breakpoint_t ), LIST_END );
325
breakpoint->number = ++breakpoint_count;
326
breakpoint->rule_sys = rule_sys;
327
breakpoint->instr = instr;
329
/* Print source position of the instruction. */
330
source_of_instr( rule_sys, instr, &line, &file, &rule );
331
printf( "Breakpoint %d in file \"%s\", line %d, rule \"%s\".\n",
332
breakpoint->number, name_in_path( file ), line, rule );
335
command_t break_command =
338
"Set a breakpoint at the specified position.\n"
340
" break RULE -- Set a breakpoint at the beginning of RULE.\n"
341
" break FILE LINE -- Set a breakpoint at LINE in FILE.\n"
342
" break LINE -- Set a breakpoint at LINE in the current rule file.\n"
343
" break -- Set a breakpoint at the current line in the current rule file.\n"
344
"The first two forms may begin with a rule system specification.\n"
345
"The last two forms can only be used in debug mode or after a rule error.\n"
346
"You can't set two breakpoints at the same position.\n"
349
/*---------------------------------------------------------------------------*/
352
do_list( string_t argument )
353
/* List breakpoints. */
355
breakpoint_t *breakpoint;
359
parse_end( &argument );
361
if (breakpoints.first == NULL)
362
printf( "No breakpoints.\n" );
363
FOREACH( breakpoint, breakpoints )
365
source_of_instr( breakpoint->rule_sys, breakpoint->instr,
366
&line, &file, &rule );
367
printf( "Breakpoint %d in file \"%s\", line %d, rule \"%s\".\n",
368
breakpoint->number, name_in_path( file ), line, rule );
372
command_t list_command =
375
"List all breakpoints.\n"
379
/*---------------------------------------------------------------------------*/
382
init_breakpoints( int_t rule_sys_count, rule_sys_name_t rule_sys[] )
383
/* Initialise this module.
384
* Pass the number of rule systems in RULE_SYS_COUNT
385
* and their names in RULE_SYS. */
387
rule_system_count = rule_sys_count;
388
rule_systems = rule_sys;
389
clear_list( &breakpoints );
392
/*---------------------------------------------------------------------------*/
395
terminate_breakpoints( void )
396
/* Terminate this module. */
398
delete_all_breakpoints();
401
/* End of file. =============================================================*/