mirror of
https://git.code.sf.net/p/fuse-emulator/fuse
synced 2026-01-27 01:41:34 +03:00
321 lines
9.6 KiB
Plaintext
321 lines
9.6 KiB
Plaintext
/* commandy.y: Parse a debugger command
|
|
Copyright (c) 2002-2018 Philip Kendall, Sergio Baldoví
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
Author contact information:
|
|
|
|
E-mail: philip-fuse@shadowmagic.org.uk
|
|
|
|
*/
|
|
|
|
%{
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h> /* Needed by NetBSD yacc */
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "debugger/debugger.h"
|
|
#include "debugger/debugger_internals.h"
|
|
#include "mempool.h"
|
|
#include "ui/ui.h"
|
|
#include "z80/z80.h"
|
|
#include "z80/z80_macros.h"
|
|
|
|
#define YYDEBUG 1
|
|
#define YYERROR_VERBOSE
|
|
|
|
%}
|
|
|
|
%union {
|
|
|
|
int token;
|
|
|
|
libspectrum_dword integer;
|
|
char *string;
|
|
|
|
debugger_breakpoint_type bptype;
|
|
debugger_breakpoint_life bplife;
|
|
struct { libspectrum_word mask, value; } port;
|
|
struct { int source; int page; int offset; } location;
|
|
|
|
debugger_expression* exp;
|
|
|
|
}
|
|
|
|
%debug
|
|
|
|
/* Tokens as returned from the Flex scanner (commandl.l) */
|
|
|
|
/* Some tokens are named DEBUGGER_* to avoid clashes with <windows.h> */
|
|
|
|
%token LOGICAL_OR /* || */
|
|
%token LOGICAL_AND /* && */
|
|
%token <token> COMPARISON /* < > <= >= */
|
|
%token <token> EQUALITY /* == != */
|
|
%token <token> NEGATE /* ! ~ */
|
|
|
|
%token BASE
|
|
%token BREAK
|
|
%token TBREAK
|
|
%token CLEAR
|
|
%token COMMANDS
|
|
%token CONDITION
|
|
%token CONTINUE
|
|
%token DEBUGGER_DELETE
|
|
%token DISASSEMBLE
|
|
%token DEBUGGER_END
|
|
%token EVENT
|
|
%token EXIT
|
|
%token FINISH
|
|
%token HOOK
|
|
%token IF
|
|
%token DEBUGGER_IGNORE
|
|
%token NEXT
|
|
%token DEBUGGER_OUT
|
|
%token PORT
|
|
%token DEBUGGER_PRINT
|
|
%token READ
|
|
%token SET
|
|
%token STEP
|
|
%token TIME
|
|
%token WRITE
|
|
|
|
%token <integer> NUMBER
|
|
|
|
%token <string> STRING
|
|
%token <string> VARIABLE
|
|
|
|
%token DEBUGGER_ERROR
|
|
|
|
/* Derived types */
|
|
|
|
%type <bplife> breakpointlife
|
|
%type <bptype> breakpointtype
|
|
%type <port> breakpointport
|
|
%type <location> breakpointlocation
|
|
%type <bptype> portbreakpointtype
|
|
%type <integer> numberorpc
|
|
%type <integer> number
|
|
|
|
%type <exp> optionalcondition
|
|
|
|
%type <exp> expressionornull
|
|
%type <exp> expression;
|
|
|
|
%type <string> debuggercommand
|
|
%type <string> debuggercommands
|
|
|
|
/* Operator precedences */
|
|
|
|
/* Low precedence */
|
|
|
|
%left LOGICAL_OR
|
|
%left LOGICAL_AND
|
|
%left '|'
|
|
%left '^'
|
|
%left '&'
|
|
%left EQUALITY
|
|
%left COMPARISON
|
|
%left '+' '-'
|
|
%left '*' '/'
|
|
%right NEGATE /* Unary minus, unary plus, !, ~ */
|
|
|
|
/* High precedence */
|
|
|
|
%%
|
|
|
|
input: /* empty */
|
|
| command
|
|
| error
|
|
| input '\n' command
|
|
;
|
|
|
|
command: BASE number { debugger_output_base = $2; }
|
|
| breakpointlife breakpointtype breakpointlocation optionalcondition {
|
|
debugger_breakpoint_add_address( $2, $3.source, $3.page, $3.offset,
|
|
0, $1, $4 );
|
|
}
|
|
| breakpointlife PORT portbreakpointtype breakpointport optionalcondition {
|
|
int mask = $4.mask;
|
|
if( mask == 0 ) mask = ( $4.value < 0x100 ? 0x00ff : 0xffff );
|
|
debugger_breakpoint_add_port( $3, $4.value, mask, 0, $1, $5 );
|
|
}
|
|
| breakpointlife TIME number optionalcondition {
|
|
debugger_breakpoint_add_time( DEBUGGER_BREAKPOINT_TYPE_TIME,
|
|
$3, 0, $1, $4 );
|
|
}
|
|
| breakpointlife EVENT STRING ':' STRING optionalcondition {
|
|
debugger_breakpoint_add_event( DEBUGGER_BREAKPOINT_TYPE_EVENT,
|
|
$3, $5, 0, $1, $6 );
|
|
}
|
|
| breakpointlife EVENT STRING ':' '*' optionalcondition {
|
|
debugger_breakpoint_add_event( DEBUGGER_BREAKPOINT_TYPE_EVENT,
|
|
$3, "*", 0, $1, $6 );
|
|
}
|
|
| CLEAR numberorpc { debugger_breakpoint_clear( $2 ); }
|
|
| COMMANDS number '\n' debuggercommands DEBUGGER_END { debugger_breakpoint_set_commands( $2, $4 ); }
|
|
| CONDITION NUMBER expressionornull {
|
|
debugger_breakpoint_set_condition( $2, $3 );
|
|
}
|
|
| CONTINUE { debugger_run(); }
|
|
| DEBUGGER_DELETE { debugger_breakpoint_remove_all(); }
|
|
| DEBUGGER_DELETE number { debugger_breakpoint_remove( $2 ); }
|
|
| DISASSEMBLE number { ui_debugger_disassemble( $2 ); }
|
|
| EXIT expressionornull { debugger_exit_emulator( $2 ); }
|
|
| FINISH { debugger_breakpoint_exit(); }
|
|
| HOOK NUMBER expression { debugger_breakpoint_set_hook( $2, $3 ); }
|
|
| DEBUGGER_IGNORE NUMBER number {
|
|
debugger_breakpoint_ignore( $2, $3 );
|
|
}
|
|
| NEXT { debugger_next(); }
|
|
| DEBUGGER_OUT number NUMBER { debugger_port_write( $2, $3 ); }
|
|
| DEBUGGER_PRINT number { printf( "0x%x\n", $2 ); }
|
|
| SET NUMBER number { debugger_poke( $2, $3 ); }
|
|
| SET VARIABLE number { debugger_variable_set( $2, $3 ); }
|
|
| SET STRING ':' STRING number { debugger_system_variable_set( $2, $4, $5 ); }
|
|
| STEP { debugger_step(); }
|
|
;
|
|
|
|
breakpointlife: BREAK { $$ = DEBUGGER_BREAKPOINT_LIFE_PERMANENT; }
|
|
| TBREAK { $$ = DEBUGGER_BREAKPOINT_LIFE_ONESHOT; }
|
|
;
|
|
|
|
breakpointtype: /* empty */ { $$ = DEBUGGER_BREAKPOINT_TYPE_EXECUTE; }
|
|
| READ { $$ = DEBUGGER_BREAKPOINT_TYPE_READ; }
|
|
| WRITE { $$ = DEBUGGER_BREAKPOINT_TYPE_WRITE; }
|
|
;
|
|
|
|
breakpointport: number { $$.mask = 0; $$.value = $1; }
|
|
| number ':' number { $$.mask = $1; $$.value = $3; }
|
|
;
|
|
|
|
breakpointlocation: numberorpc { $$.source = memory_source_any; $$.offset = $1; }
|
|
| STRING ':' number ':' number {
|
|
$$.source = memory_source_find( $1 );
|
|
if( $$.source == -1 ) {
|
|
char buffer[80];
|
|
snprintf( buffer, 80, "unknown memory source \"%s\"", $1 );
|
|
yyerror( buffer );
|
|
YYERROR;
|
|
}
|
|
$$.page = $3;
|
|
$$.offset = $5;
|
|
}
|
|
|
|
portbreakpointtype: READ { $$ = DEBUGGER_BREAKPOINT_TYPE_PORT_READ; }
|
|
| WRITE { $$ = DEBUGGER_BREAKPOINT_TYPE_PORT_WRITE; }
|
|
;
|
|
|
|
optionalcondition: /* empty */ { $$ = NULL; }
|
|
| IF expression { $$ = $2; }
|
|
;
|
|
|
|
numberorpc: /* empty */ { $$ = PC; }
|
|
| number { $$ = $1; }
|
|
;
|
|
|
|
expressionornull: /* empty */ { $$ = NULL; }
|
|
| expression { $$ = $1; }
|
|
;
|
|
|
|
number: expression { $$ = debugger_expression_evaluate( $1 ); }
|
|
;
|
|
|
|
expression: NUMBER { $$ = debugger_expression_new_number( $1, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| STRING ':' STRING { $$ = debugger_expression_new_system_variable( $1, $3, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| VARIABLE { $$ = debugger_expression_new_variable( $1, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| '(' expression ')' { $$ = $2; }
|
|
| '[' expression ']' {
|
|
$$ = debugger_expression_new_unaryop( DEBUGGER_TOKEN_DEREFERENCE, $2, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| '+' expression %prec NEGATE { $$ = $2; }
|
|
| '-' expression %prec NEGATE {
|
|
$$ = debugger_expression_new_unaryop( '-', $2, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| NEGATE expression {
|
|
$$ = debugger_expression_new_unaryop( $1, $2, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| expression '+' expression {
|
|
$$ = debugger_expression_new_binaryop( '+', $1, $3, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| expression '-' expression {
|
|
$$ = debugger_expression_new_binaryop( '-', $1, $3, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| expression '*' expression {
|
|
$$ = debugger_expression_new_binaryop( '*', $1, $3, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| expression '/' expression {
|
|
$$ = debugger_expression_new_binaryop( '/', $1, $3, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| expression EQUALITY expression {
|
|
$$ = debugger_expression_new_binaryop( $2, $1, $3, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| expression COMPARISON expression {
|
|
$$ = debugger_expression_new_binaryop( $2, $1, $3, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| expression '&' expression {
|
|
$$ = debugger_expression_new_binaryop( '&', $1, $3, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| expression '^' expression {
|
|
$$ = debugger_expression_new_binaryop( '^', $1, $3, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| expression '|' expression {
|
|
$$ = debugger_expression_new_binaryop( '|', $1, $3, debugger_memory_pool );
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| expression LOGICAL_AND expression {
|
|
$$ = debugger_expression_new_binaryop(
|
|
DEBUGGER_TOKEN_LOGICAL_AND, $1, $3, debugger_memory_pool
|
|
);
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
| expression LOGICAL_OR expression {
|
|
$$ = debugger_expression_new_binaryop(
|
|
DEBUGGER_TOKEN_LOGICAL_OR, $1, $3, debugger_memory_pool
|
|
);
|
|
if( !$$ ) YYABORT;
|
|
}
|
|
;
|
|
|
|
debuggercommands: debuggercommand { $$ = $1; }
|
|
| debuggercommands debuggercommand {
|
|
$$ = mempool_new( debugger_memory_pool, char, strlen( $1 ) + strlen( $2 ) + 2 );
|
|
sprintf( $$, "%s\n%s", $1, $2 );
|
|
}
|
|
|
|
debuggercommand: STRING '\n'
|
|
|
|
%%
|