📄 yydebug.c
字号:
/*@A (C) 1992 Allen I. Holub */
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h> /* ANSI/UNIX time functions. */
#include <sys/timeb.h> /* ANSI/UNIX time functions. */
#include <signal.h> /* Needed by signal. */
#include <stdarg.h> /* ANSI variable-argument lists. */
#include <io.h> /* Prototypes for access(). */
#include <string.h> /* Prototypes for string functions. */
#include <stdlib.h> /* Prototypes for other library functions. */
#include <tools/debug.h> /* Various macros. */
#include <curses.h> /* Window functions. */
#include <tools/l.h> /* Prototypes for all of l.lib, including all */
/* functions in the current file. */
extern char *yytext; /* Generated by LeX and lex. */
extern int yylineno;
extern int yyleng;
/* If your system doesn't have an <stdarg.h>, use the following:
*
* typedef char *va_list;
* #define va_start(arg_ptr,first) arg_ptr = (va_list)&first + sizeof(first)
* #define va_arg(arg_ptr,type) ((type*)(arg_ptr += sizeof(type)))[-1]
* #define va_end()
*----------------------------------------------------------------------
* The following macros take care of system dependencies. They assume a 25-line
* screen on the IBM and a 24-line screen under Unix. Code put inside an MS()
* macro compiles only if a MSDOS compiler is being used. Code in a UNIX()
* macro compiles only if a UNIX compiler is being used. The NEWLINE define
* takes care of a bug in the UNIX curses package that isn't present in the
* DOS version presented in this book (it clears the bottom line after a
* scroll). box.h (in Appendix A) holds #defines for the IBM Box-drawing
* characters. #define NOT_IBM_PC to use the more portable defines in that
* file ('+' is used for corners, '|' for vertical lines, and '-' for
* horizontal ones) rather than the less-portable IBM graphics characters.
* fcntl() is also used only in UNIX mode.
*/
#ifdef MSDOS /* An MSDOS compiler is active */
# include <tools/box.h> /* Use IBM-PC graphics characters */
# define SCRNSIZE 25
# define NEWLINE(win) (Interactive ? waddch( win, '\n') :0)
#else
# define NOT_IBM_PC /* Use dashes, vertical bars, etc. */
# include <tools/box.h>
extern int fputc(); /* system stuff */
extern int errno;
# define SCRNSIZE 24
# define NEWLINE(win) (Interactive ? (waddch( win, '\n'), wclrtoeol(win))\
: 0 )
#endif
/* Prototypes for local statics: */
#if ( 0 UNIX(+1) ) /* UNIX compilers only */
PRIVATE void kbready ();
PRIVATE WINDOW *boxwin ();
#else
PRIVATE WINDOW *boxwin (int lines, int cols, int y_start,
int x_start, char *title );
#endif
/* ----------------------------------------------------------------------
* Defines for the windows. STACK_TOP is the top line of the stack window.
* DEFSTACK is the default size of the text area of the stack window.
* STACK_WINSIZE is the height of the stack window, including the border. IO_TOP
* is the top line of both the I/O and comments windows, and IO_WINSIZE is the
* height of the text area of those windows. It should use the whole screen
* less the area used for the stack and prompt windows.
*/
#define STACK_TOP 0
#define DEFSTACK 11 /* Stacksize=DEFSTACK by default. */
#define STACK_WINSIZE (Stacksize +2)
#define PROMPT_TOP (SCRNSIZE - 3)
#define PROMPT_WINSIZE 3
#define IO_TOP (STACK_WINSIZE-1)
#define IO_WINSIZE ((SCRNSIZE - (STACK_WINSIZE + PROMPT_WINSIZE)) + 2)
#define TOKEN_WIDTH 22 /* Width of token window including border. */
#define PRINTWIDTH 79 /* Only this many characters are printed on each
* line by the write-screen (w) command. Extra
* characters are truncated.
*/
#define ESC 0x1b /* ASCII ESC character. */
/* ----------------------------------------------------------------------
* Breakpoints. A breakpoint is set with a 'b' command. It causes automatic-mode
* operation to terminate immediately before applying a specific production or
* when a specified symbol is on the top of stack. P_breakpoint holds the
* production breakpoint; T_breakpoint holds the top-of-stack breakpoint;
* I_breakpoint is the input breakpoint. The former is an int because it's
* always a number. The latter two are strings because they can be symbolic
* names as well as numbers. The last variable, L_breakpoint, is the input-
* line breakpoint.
*/
#define BRKLEN 33 /* Longest lexeme recognized in a breakpoint + 1. */
PRIVATE int P_breakpoint = -1 ;
PRIVATE int L_breakpoint = -1 ;
PRIVATE char S_breakpoint[ BRKLEN ] = { '\0' } ;
PRIVATE char I_breakpoint[ BRKLEN ] = { '\0' } ;
/*----------------------------------------------------------------------
* I've attempted to isolate these routines as much as possible from the actual
* parser. They do need to know where all the stacks are, however. The following
* variables are initialized at run-time by an access routine [yy_init_debug()]
* and are used to access static variables in the parser itself. Note that the
* addresses of the stack pointers are stored, not the contents of the stack
* pointers.
*/
PRIVATE int Abort ; /* Force input routine to return EOI. */
PRIVATE char *Vstack ; /* Base address of value stack (or NULL */
/* if called by llama-generated parser).*/
PRIVATE int Vsize ; /* Size of one element of value stack. */
PRIVATE char **Dstack ; /* Base address of debug (symbol) stack.*/
PRIVATE char ***P_dsp ; /* Pointer to debug-stack pointer. */
PRIVATE int *Sstack ; /* Base address of state stack. */
PRIVATE int **P_sp ; /* Pointer to state-stack pointer. */
PRIVATE int Depth ; /* Stack depth (all three stacks). */
/*----------------------------------------------------------------------
* The following variables are all used internally
*/
PRIVATE WINDOW *Stack_window ; /* Windows for the debugging screen */
PRIVATE WINDOW *Prompt_window ;
PRIVATE WINDOW *Code_window ;
PRIVATE WINDOW *Comment_window ;
PRIVATE WINDOW *Token_window ;
PRIVATE int Stacksize = DEFSTACK;/* Number of active lines in the stack */
/* window (doesn't include border). */
PRIVATE int Onumele = 0; /* Number of elements on the stack. */
PRIVATE int Interactive = 1; /* Interactive mode (not n or N). */
PRIVATE int Singlestep = 1; /* Single step through parse if true. */
PRIVATE long Delay = 0L; /* Amount of time to wait after printing */
/* each stack update when not single */
/* stepping (milliseconds). */
PRIVATE int Inp_fm_file = 0; /* 1 if input file is open. */
PRIVATE FILE *Log = NULL; /* Pointer to the log file if one is open. */
PRIVATE int No_comment_pix = 0; /* 1 if no comment-window output is printed.*/
PRIVATE int No_stack_pix = 0; /* 1 if no stack pictures are to be printed */
/* in the log file.*/
PRIVATE int Horiz_stack_pix = 0; /* 1 if stack pictures are printed horiz- */
/* ontally in the log file. */
PRIVATE int Parse_pix; /* if(Horiz_stack_pix), print state stack. */
PRIVATE int Sym_pix; /* if(Horiz_stack_pix), print symbol stack. */
PRIVATE int Attr_pix; /* if(Horiz_stack_pix), print attrib. stack.*/
#if (0 UNIX(+1) ) /*--------------- UNIX SYSTEM V ONLY --------------------*/
/* Since MS-DOS has a system call that
* gives the keyboard status, detecting
* if a key has been pressed without
* reading the character is easy. In
* UNIX you must use SIGIO to set a
* flag (Char_avail). kbready() is the
* SIGIO exception handler.
*/
PRIVATE int Char_avail = 0;
#define kbhit() Char_avail
#else /*-------------------- MSDOS VERSION ONLY -------------------------*/
extern int kbhit ( void ); /* Microsoft function. returns 1 if a */
/* character is waiting to be read */
/* from the keyboard buffer. This */
/* function is provided in most */
/* MS-DOS compiler's libraries. */
/* The Map[] array converts IBM box-drawing characters to something that's
* printable. The corners are converted to plus signs, horizontal lines go to
* dashes, and vertical lines map to vertical bars. The conv() subroutine is
* passed a character and returns a mapped character. It must be a subroutine
* because of the way that it's used below. It would have unacceptable
* side-effects if rewritten as a macro.
*/
PRIVATE unsigned char Map[] =
{
'|', '+', '+', '+', '+', '+', '+', '|', '+', '+', '+', '+', '+', '+',
'+', '+', '+', '-', '+', '+', '+', '+', '+', '+', '+', '+', '=', '+',
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+'
};
PRIVATE int conv(c)
int c;
{
return (VERT <= c && c <= UL) ? Map[c - VERT] : c ;
}
#endif /*--------------------------------------------------------------*/
PUBLIC int yy_init_debug(sstack, p_sp, dstack, p_dsp, vstack, v_ele_size, depth)
int *sstack; /* Base address of state stack. */
int **p_sp; /* Address of state-stack pointer. */
char **dstack; /* Address of debug stack. */
char ***p_dsp; /* Address of debug-stack pointer. */
void *vstack; /* Base address of value stack or NULL for LLama. */
int v_ele_size; /* Size of one element of value stack. */
int depth; /* Number of elements in all three stacks. */
{
/* Initialize for interactive I/O for curses. Return 1 on a successful
* initialization, 0 otherwise.
*/
char buf[80];
UNIX( int flags; )
UNIX( signal( SIGIO, kbready ); )
UNIX( flags = fcntl( fileno(stdin), F_GETFL, 0 ); )
UNIX( fcntl( fileno(stdin), F_SETFL, flags | FASYNC ); )
Sstack = sstack;
Dstack = dstack;
Vstack = (char *) vstack;
Vsize = v_ele_size;
P_sp = p_sp;
P_dsp = p_dsp;
Depth = depth;
Abort = 0;
initscr();
signal( SIGINT, (void (*)(int)) die_a_horrible_death );
noecho(); /* Don't echo input characters automatically. */
crmode(); /* Don't buffer input. */
MS( nosave(); ) /* Don't save region under windows (my curses only). */
Stack_window = boxwin( STACK_WINSIZE, 80, STACK_TOP, 0, "[stack]" );
Comment_window = boxwin( IO_WINSIZE, 40, IO_TOP, 0, "[comments]" );
Code_window = boxwin( IO_WINSIZE, 41, IO_TOP, 39, "[output]" );
Token_window = boxwin(PROMPT_WINSIZE, TOKEN_WIDTH, PROMPT_TOP,
80 - TOKEN_WIDTH, "[lookahead]" );
Prompt_window = boxwin(PROMPT_WINSIZE, (80 - TOKEN_WIDTH) + 1,
PROMPT_TOP, 0, "[prompts]" );
scrollok( Stack_window, TRUE );
scrollok( Comment_window, TRUE );
scrollok( Code_window, TRUE );
scrollok( Prompt_window, TRUE );
scrollok( Token_window, FALSE );
Onumele = 0;
while( !Inp_fm_file )
{
/* If you don't have an input file yet, get one. yyprompt() prints the
* prompt in the PROMPT window, and fills buf with the reply.
*/
if( !yyprompt( "Input file name or ESC to exit: ", buf, 1 ) )
{
yy_quit_debug();
return 0;
}
new_input_file( buf );
}
delay(); /* Wait for a command before proceeding */
return 1;
}
/*----------------------------------------------------------------------
* Exception handlers:
*/
#if ( 0 UNIX(+1) ) /* UNIX compilers only */
PRIVATE void kbready( ) /* Called when new character is available. */
{
Char_avail = 1;
}
#endif
PRIVATE void die_a_horrible_death() /* Come here on a SIGINT */
{ /* or 'q' command. */
signal( SIGINT, SIG_IGN );
yy_quit_debug();
exit( 0 );
}
PUBLIC void yy_quit_debug() /* Normal termination. */
{
echo(); /* Turn echo and editing back on. */
nocrmode();
move( 24, 0 ); /* Put the cursor on the bottom of the screen. */
refresh();
endwin(); /* Turn off curses. */
if( Log )
fclose( Log );
stop_prnt();
signal( SIGINT, SIG_DFL );
}
/*----------------------------------------------------------------------*/
PRIVATE WINDOW *boxwin( lines, cols, y_start, x_start, title )
int lines;
int cols;
int y_start;
int x_start;
char *title;
{
/* This routine works just like the newwin() except that the window has a
* box around it that won't be destroyed by writes to the window. It
* accomplishes this feat by creating two windows, one inside the other,
* with a box drawn in the outer one. It prints the optional title centered
* on the top line of the box. Set title to NULL (or "") if you don't want
* a title. Note that all windows are made subwindows of the default window
* to facilitate the print-screen command.
*/
WINDOW *outer;
outer = subwin( stdscr, lines, cols, y_start, x_start);
box( outer, VERT, HORIZ );
if( title && *title )
{
wmove ( outer, 0, (cols - strlen(title))/2 );
wprintw( outer, "%s", title );
}
wrefresh ( outer );
return subwin( outer, lines-2, cols-2, y_start+1, x_start+1 );
}
/*----------------------------------------------------------------------*/
PUBLIC int yy_get_args( argc, argv )
int argc;
char **argv;
{
/* Scan argv arguments for the debugging options and remove the arguments
* from argv. Recognized arguments are:
*
* -sN Set stack-window size to N lines. The size of the other windows
* scale accordingly. The stack window is not permitted to get so
* large that the other windows will disappear, however.
*
* The first argument that doesn't begin with a minus sign is taken to be
* the input file name. That name is not removed from argv. All other
* arguments are ignored and are not removed from argv, so you can process
* them in your own program. This routine prints an error message and
* terminates the program if it can't open the specified input file.
* Command-line processing stops immediately after the file name is
* processed. So, given the line:
*
* program -x -s15 -y foo -s1 bar
*
* Argv is modified to:
*
* program -x -y foo -s1 bar
*
* The file "foo" will have been opened for input and the stack window will
* be 15 lines high. Return new value of argc that reflects the removed
* arguments;
*/
char **newargv;
char **oldargv = argv;
char *filename = NULL;
int ssize = DEFSTACK;
newargv = ++argv;
for( --argc; --argc >= 0; ++argv )
{
if( argv[0][0] != '-' )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -