/* commandy.y: Parse a debugger command Copyright (c) 2002-2004 Philip Kendall $Id: commandy.y,v 1.43 2007/02/02 16:21:53 pak21 Exp $ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Author contact information: E-mail: philip-fuse@shadowmagic.org.uk */ %{ #include #include /* Needed by NetBSD yacc */ #include #include #include "debugger.h" #include "debugger_internals.h" #include "ui/ui.h" #include "z80/z80.h" #include "z80/z80_macros.h" #define YYDEBUG 1 #define YYERROR_VERBOSE %} %union { int token; int reg; libspectrum_dword integer; debugger_breakpoint_type bptype; debugger_breakpoint_life bplife; struct { int value1; libspectrum_word value2; } pair; debugger_expression* exp; } /* Tokens as returned from the Flex scanner (commandl.l) */ %token LOGICAL_OR /* || */ %token LOGICAL_AND /* && */ %token COMPARISION /* < > <= >= */ %token EQUALITY /* == != */ %token NEGATE /* ! ~ */ %token TIMES_DIVIDE /* * / */ %token BASE %token BREAK %token TBREAK %token CLEAR %token CONDITION %token CONTINUE %token DELETE %token DISASSEMBLE %token FINISH %token IF %token IGNORE %token NEXT %token DEBUGGER_OUT /* Different name to avoid clashing with OUT from windows.h */ %token PORT %token READ %token SET %token STEP %token TIME %token WRITE %token PAGE %token REGISTER %token NUMBER %token ERROR /* Derived types */ %type breakpointlife %type breakpointtype %type pageornumber %type breakpointpair %type portbreakpointtype %type numberorpc %type number %type optionalcondition %type expressionornull %type expression; /* Operator precedences */ /* Low precedence */ %left LOGICAL_OR %left LOGICAL_AND %left '|' %left '^' %left '&' %left EQUALITY %left COMPARISION %left '+' '-' %left TIMES_DIVIDE %right NEGATE /* Unary minus, unary plus, !, ~ */ /* High precedence */ %% input: /* empty */ | command | error ; command: BASE number { debugger_output_base = $2; } | breakpointlife breakpointtype breakpointpair optionalcondition { debugger_breakpoint_add_address( $2, $3.value1, $3.value2, 0, $1, $4 ); } | breakpointlife PORT portbreakpointtype breakpointpair optionalcondition { int mask; libspectrum_word port; mask = $4.value1; port = $4.value2; if( mask == -1 ) mask = ( port < 0x100 ? 0x00ff : 0xffff ); debugger_breakpoint_add_port( $3, port, mask, 0, $1, $5 ); } | breakpointlife TIME number optionalcondition { debugger_breakpoint_add_time( DEBUGGER_BREAKPOINT_TYPE_TIME, $3, 0, $1, $4 ); } | CLEAR numberorpc { debugger_breakpoint_clear( $2 ); } | CONDITION NUMBER expressionornull { debugger_breakpoint_set_condition( $2, $3 ); } | CONTINUE { debugger_run(); } | DELETE { debugger_breakpoint_remove_all(); } | DELETE number { debugger_breakpoint_remove( $2 ); } | DISASSEMBLE number { ui_debugger_disassemble( $2 ); } | FINISH { debugger_breakpoint_exit(); } | IGNORE NUMBER number { debugger_breakpoint_ignore( $2, $3 ); } | NEXT { debugger_next(); } | DEBUGGER_OUT number NUMBER { debugger_port_write( $2, $3 ); } | SET NUMBER number { debugger_poke( $2, $3 ); } | SET REGISTER number { debugger_register_set( $2, $3 ); } | 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; } ; breakpointpair: numberorpc { $$.value1 = -1; $$.value2 = $1; } | pageornumber ':' number { $$.value1 = $1; $$.value2 = $3; } ; pageornumber: PAGE { $$ = $1; } | number { $$ = $1; } 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 ); if( !$$ ) YYABORT; } | REGISTER { $$ = debugger_expression_new_register( $1 ); if( !$$ ) YYABORT; } | '(' expression ')' { $$ = $2; } | '+' expression %prec NEGATE { $$ = $2; } | '-' expression %prec NEGATE { $$ = debugger_expression_new_unaryop( '-', $2 ); if( !$$ ) YYABORT; } | NEGATE expression { $$ = debugger_expression_new_unaryop( $1, $2 ); if( !$$ ) YYABORT; } | expression '+' expression { $$ = debugger_expression_new_binaryop( '+', $1, $3 ); if( !$$ ) YYABORT; } | expression '-' expression { $$ = debugger_expression_new_binaryop( '-', $1, $3 ); if( !$$ ) YYABORT; } | expression TIMES_DIVIDE expression { $$ = debugger_expression_new_binaryop( $2, $1, $3 ); if( !$$ ) YYABORT; } | expression EQUALITY expression { $$ = debugger_expression_new_binaryop( $2, $1, $3 ); if( !$$ ) YYABORT; } | expression COMPARISION expression { $$ = debugger_expression_new_binaryop( $2, $1, $3 ); if( !$$ ) YYABORT; } | expression '&' expression { $$ = debugger_expression_new_binaryop( '&', $1, $3 ); if( !$$ ) YYABORT; } | expression '^' expression { $$ = debugger_expression_new_binaryop( '^', $1, $3 ); if( !$$ ) YYABORT; } | expression '|' expression { $$ = debugger_expression_new_binaryop( '|', $1, $3 ); if( !$$ ) YYABORT; } | expression LOGICAL_AND expression { $$ = debugger_expression_new_binaryop( DEBUGGER_TOKEN_LOGICAL_AND, $1, $3 ); if( !$$ ) YYABORT; } | expression LOGICAL_OR expression { $$ = debugger_expression_new_binaryop( DEBUGGER_TOKEN_LOGICAL_OR, $1, $3 ); if( !$$ ) YYABORT; } ; %%