/*-------------------------------------------------------------------------*/
/* Prolog to Wam Compiler INRIA Rocquencourt - ChLoE Project */
/* C Run-time Daniel Diaz - 1994 */
/* */
/* Prolog/Wam Debugger */
/* */
/* debugger.c */
/*-------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wam_engine.h"
#define DEBUGGER
#include "debugger.h"
LibPrototype(extern long strtol())
/*---------------------------------*/
/* Constants */
/*---------------------------------*/
#define CALL 1
#define EXIT 2
#define FAIL 4
#define REDO 8
#define WAMI 16
#define MAX_SPY_TBL_SIZE 64
#define DEFAULT_DEBUG_STACK_SZ 10240 /* in WamWords */
#define DEBUG_STACK_ENV_VAR_NAME "DEBUGSZ"
#define BANK_NAME_OFFSET_LENGTH 13
#define HEXADECIMAL_LENGTH 10
#define DECIMAL_LENGTH 10
#define VALUE_PART_LENGTH BANK_NAME_OFFSET_LENGTH
#define ERR_ALLOC_DEBUG "Memory allocation fault (in debugger)"
#define ERR_DEBUG_STACK_OVERFLOW "debug stack overflow"
#define SEPARATOR_LIST " ,[]"
#define ABORT X61626F7274
#define DBG_EXEC X6462675F65786563
/*---------------------------------*/
/* Type Definitions */
/*---------------------------------*/
typedef enum
{
DEBUGGED,
EXTERNAL,
DYNAMIC
}PDbgTyp;
typedef struct runinf *PRunInf;
typedef struct runinf /* one env = info call of f/n */
{
PRunInf last_env; /* previous env in the stack */
PRunInf caller_env; /* env caller of this one */
AtomInf *atom; /* functor atom (f) */
int arity; /* arity (n) */
PDbgTyp type; /* debugged(local)/external/dyn */
Bool aux_pred; /* is it an auxiliary predicate?*/
WamCont cp; /* copy of CP before the call */
WamWord *e; /* copy of E before the call */
WamWord *b; /* copy of B before the call */
int invoc_nb; /* invocation number */
int indice_nb; /* indice number */
WamWord word; /* term: <STC,&f_n> or <CST,f> */
union /* or heap term (if dynamic) */
{ /* if !dynamic and arity > 0 */
WamWord f_n; /* word f/n */
Bool first_clause; /* first clause (try) if dyn */
}x;
}RunInf;
typedef Bool (*FctPtr)();
typedef struct
{
char *name;
FctPtr fct;
}InfCmd;
/*---------------------------------*/
/* Global Variables */
/*---------------------------------*/
static AtomInf *atom_debug;
static AtomInf *atom_nodebug;
static AtomInf *atom_trace;
static AtomInf *atom_call;
static AtomInf *atom_exit;
static AtomInf *atom_fail;
static AtomInf *atom_redo;
static AtomInf *debug_mode;
static RunInf *debug_stack=NULL;
static RunInf *end_debug_stack;
static RunInf *top_stack;
static RunInf *top_env;
static int invoc_nb;
static char *spy_tbl;
static int skip_invoc_nb;
static Bool leap_mode;
static Bool exact_trace;
static int wam_curr_inst;
static int wam_next_inst;
static int leash_option;
static int depth;
static Bool redo;
static Bool catch_fail;
static int nb_read_arg;
static char read_arg[30][80];
static char *envir_name[]=ENVIR_NAMES;
static char *choice_name[]=CHOICE_NAMES;
static char *trail_tag_name[]=TRAIL_TAG_NAMES;
static WamWord reg_copy[NB_OF_REGS];
/*---------------------------------*/
/* Function Prototypes */
/*---------------------------------*/
static
RunInf *Find_Non_Determin_Env (RunInf *top,WamWord *b);
static
void Call_Port (AtomInf *atom,int arity,PDbgTyp type);
static
void Exit_Port (Bool from_dynamic);
static
void Fail_Port (void);
static
void Redo_Port (void);
static
void Read_Command (int port,Bool read_cmd,char *str_next_inst);
static
void Scan_Command (char *source_str);
static
FctPtr Find_Function (void);
static
Bool Creep (void);
static
Bool Skip (int port);
static
Bool Leap (void);
static
Bool Abort (void);
static
Bool Goals_GoalsB (void);
static
void One_Goal (int nb,RunInf *top_last_e,
RunInf *top_caller_e,WamWord *b);
static
Bool Leash (void);
static
Bool NoDebug (void);
static
Bool Debugging (void);
static
Bool Spy_NoSpy_NoSpyAll (void);
static
Bool Exec_Prolog_Goal (void);
static
Bool Depth (void);
static
Bool Exact_NoExact (void);
static
Bool Write_Data_Modify (void);
static
Bool Where (void);
static
Bool Dereference (void);
static
Bool Environment (void);
static
Bool Backtrack (void);
static
WamWord *Read_Bank_Adr (Bool only_stack,int arg_nb,
char **bank_name);
static
int Read_Integer (int arg_nb);
static
void Print_Bank_Name_Offset(char *prefix,char *bank_name,int offset);
static
void Print_Wam_Word (WamWord *word_adr);
static
void Modify_Wam_Word (WamWord *word_adr);
static
WamWord *Detect_Stack (WamWord *adr,char **stack_name);
static
Bool Instruction (void);
static
Bool Help (void);
#define math_max(x,y) (((x)>(y)) ? (x) : (y))
#define Y_Storing_Invoc_Nb(e) (Y(e,3)) /* see call.pl */
/*-------------------------------------------------------------------------*/
/* INIT_DEBUGGER */
/* */
/*-------------------------------------------------------------------------*/
void Init_Debugger(void)
{
char *p;
int x=DEFAULT_DEBUG_STACK_SZ;
if (debug_stack==NULL)
{
p=(char *) Lib1(getenv,DEBUG_STACK_ENV_VAR_NAME);
if (p && *p)
{
x=Lib1(atoi,p);
x=KBytes_To_Wam_Words(x);
}
if ((debug_stack=(RunInf *) Lib1(malloc,x*sizeof(WamWord)))==NULL)
Fatal_Error(ERR_ALLOC_DEBUG);
end_debug_stack=(RunInf *) ((WamWord *) debug_stack+x);
spy_tbl=Hash_Table(MAX_SPY_TBL_SIZE,sizeof(long),sizeof(long));
if (spy_tbl==NULL)
Fatal_Error(ERR_ALLOC_DEBUG);
atom_debug =Create_Atom("debug");
atom_nodebug=Create_Atom("nodebug");
atom_trace =Create_Atom("trace");
atom_call =Create_Atom("call");
atom_exit =Create_Atom("exit");
atom_fail =Create_Atom("fail");
atom_redo =Create_Atom("redo");
}
top_stack=top_env=debug_stack;
top_env->atom =Create_Atom("????????"); /* dummy env */
top_env->arity =0;
top_env->type =EXTERNAL;
top_env->cp =NULL;
top_env->e =NULL;
top_env->b =NULL;
top_env->indice_nb=0;
invoc_nb=1;
debug_mode =atom_nodebug;
leap_mode =FALSE;
skip_invoc_nb=0;
exact_trace =FALSE;
wam_curr_inst=0;
wam_next_inst=0;
depth =10;
leash_option =CALL|EXIT|FAIL|REDO;
redo =FALSE;
catch_fail =FALSE;
}
/*-------------------------------------------------------------------------*/
/* DEBUG_SET_MODE */
/* */
/*-------------------------------------------------------------------------*/
Bool Debug_Set_Mode(AtomInf *mode)
{
if (mode!=atom_debug && mode!=atom_trace && mode!=atom_nodebug)
return FALSE;
top_stack=top_env=debug_stack;
leap_mode=(mode==atom_debug); /* always to reinitialize */
skip_invoc_nb=0;
invoc_nb =1;
wam_curr_inst=0;
wam_next_inst=0;
redo =FALSE;
catch_fail =FALSE;
if (mode!=debug_mode)
{
debug_mode=mode;
Debug_Display_Mode();
}
return TRUE;
}
/*-------------------------------------------------------------------------*/
/* DEBUG_GET_MODE */
/* */
/*-------------------------------------------------------------------------*/
AtomInf *Debug_Get_Mode(void)
{
return debug_mode;
}
/*-------------------------------------------------------------------------*/
/* DEBUG_CLAUSE */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Clause(void)
{
if (debug_mode==atom_nodebug)
return;
if (redo && exact_trace)
Redo_Port();
}
/*-------------------------------------------------------------------------*/
/* DEBUG_BODY */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Body(void)
{
if (debug_mode==atom_nodebug)
return;
catch_fail=TRUE;
if (redo && !exact_trace)
Redo_Port();
}
/*-------------------------------------------------------------------------*/
/* DEBUG_CALL */
/* */
/* name==NULL if called predicate is dynamic (A(0) contains the pred) */
/* debug_level: -1 (don't know) 0/1/2 (no/only Prolog/Prolog + WAM insts)*/
/* (not used if called predicate is dynamic) */
/*-------------------------------------------------------------------------*/
void Debug_Call(char *name,int arity,int debug_level)
{
AtomInf *atom;
PredInf *pred;
if (debug_mode==atom_nodebug)
return;
if (name==NULL)
{
Call_Port(NULL,arity,DYNAMIC);
return;
}
atom=Create_Atom(name);
if (debug_level== -1) /* then the pred is static and public */
{
pred=Lookup_Pred(atom,arity,0);
debug_level=module_tbl[pred->owner_mod_nb].debug_level;
}
Call_Port(atom,arity,(debug_level) ? DEBUGGED : EXTERNAL);
}
/*-------------------------------------------------------------------------*/
/* DEBUG_PROCEED */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Proceed(Bool from_dynamic)
{
if (debug_mode==atom_nodebug)
return;
Exit_Port(from_dynamic);
}
/*-------------------------------------------------------------------------*/
/* DEBUG_FAIL */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Fail(void)
{
if (debug_mode==atom_nodebug)
return;
if (exact_trace || catch_fail || top_env->b>=B)
Fail_Port();
}
/*-------------------------------------------------------------------------*/
/* DEBUG_DYNAMIC_BODY */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Dynamic_Body(void)
{
int dyn_invoc_nb;
RunInf *top_bkt;
if (debug_mode==atom_nodebug)
return;
dyn_invoc_nb=Y_Storing_Invoc_Nb(E);
if (top_env->invoc_nb==dyn_invoc_nb && top_env->x.first_clause)
{ /* first time */
top_env->x.first_clause=FALSE;
return;
}
top_bkt=top_stack;
while(top_bkt->invoc_nb!=dyn_invoc_nb)
top_bkt=top_bkt->last_env;
while(top_env>debug_stack && top_env>top_bkt)
{
Read_Command(FAIL,TRUE,NULL);
top_env=top_env->caller_env;
}
top_env=top_bkt;
invoc_nb=top_env->invoc_nb+1;
Read_Command(REDO,TRUE,NULL);
}
/*-------------------------------------------------------------------------*/
/* DEBUG_HAS_FAILED_REDO */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Has_Failed_Redo(void)
{ /* used by call/1 */
RunInf *top_bkt;
if (debug_mode==atom_nodebug)
return;
top_bkt=Find_Non_Determin_Env(top_stack,B+1); /* choice point deleted */
if (top_bkt==debug_stack)
top_bkt=top_env;
if (top_bkt==debug_stack)
{
Lib1(printf,"Not enough debug information at Fail Port\n");
return;
}
while(top_env>debug_stack && top_env>=top_bkt)
{
Read_Command(FAIL,TRUE,NULL);
top_env=top_env->caller_env;
}
top_env=top_bkt;
invoc_nb=top_env->invoc_nb+1;
redo=FALSE;
Read_Command(REDO,TRUE,NULL);
}
/* synchronize with non debugged pred (after call/return/fail) */
/*-------------------------------------------------------------------------*/
/* DEBUG_PRED */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Pred(char *name,int arity)
{
AtomInf *atom;
if (debug_mode==atom_nodebug)
return;
if (top_env->type!=DEBUGGED)
{
atom=Create_Atom(name);
Call_Port(atom,arity,DEBUGGED);
}
}
/*-------------------------------------------------------------------------*/
/* DEBUG_SUB_PRED */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Sub_Pred(char *name,int arity)
{
RunInf *top;
if (debug_mode==atom_nodebug)
return;
top=top_stack;
while(top>debug_stack && (top->cp!=CP || top->e!=E))
top=top->last_env;
if (top==debug_stack || top<top_env)
{
Lib1(printf,"Not enough debug information (Redo) Exit Port\n");
return;
}
if (top->type==DEBUGGED)
return;
if (top>top_env)
{ /* fail/redo in outside */
top_env=top;
invoc_nb=top_env->invoc_nb+1;
Read_Command(REDO,FALSE,NULL);
}
/* proceed from outside */
Exit_Port(FALSE);
}
/*-------------------------------------------------------------------------*/
/* DEBUG_RETRY */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Retry(void)
{
if (debug_mode==atom_nodebug)
return;
if (top_env->type!=DEBUGGED) /* fail from outside */
Fail_Port();
}
/*-------------------------------------------------------------------------*/
/* DEBUG_WAM_INST */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Wam_Inst(char *str_next_inst)
{
if (++wam_curr_inst!=wam_next_inst)
return;
Read_Command(WAMI,TRUE,str_next_inst);
}
/*-------------------------------------------------------------------------*/
/* FIND_NON_DETERMIN_ENV */
/* */
/*-------------------------------------------------------------------------*/
static RunInf *Find_Non_Determin_Env(RunInf *top,WamWord *b)
{
while(top->b >= b)
top=top->last_env;
return top;
}
/*-------------------------------------------------------------------------*/
/* CALL_PORT */
/* */
/* if type==DYNAMIC A(0) contains the called predicate */
/*-------------------------------------------------------------------------*/
static void Call_Port(AtomInf *atom,int arity,PDbgTyp type)
{
RunInf *top,*cur_top;
WamWord *adr;
int indice_nb;
char *p=NULL;
int i;
while(top_env>debug_stack && top_env->type==EXTERNAL)
{ /* the caller cannot be EXTERNAL */
Read_Command(EXIT,TRUE,NULL);/* so they have suceeded (dynamic calls) */
top_env=top_env->caller_env;
}
indice_nb=top_env->indice_nb+1;
top_stack=Find_Non_Determin_Env(top_stack,B);
cur_top=math_max(top_stack,top_env);
top=(RunInf *) ((WamWord *) (cur_top+1)+cur_top->arity);
if (top>=end_debug_stack)
Fatal_Error(ERR_DEBUG_STACK_OVERFLOW);
if (type==DYNAMIC)
atom=Get_Functor_Arity(A(0),&arity,&adr); /* init atom */
else
p=(char *) Lib2(strchr,atom->name,'$');
top->last_env =cur_top;
top->caller_env=top_env;
top->atom =atom;
top->arity =arity;
top->type =type;
top->aux_pred =(p!=NULL && Lib3(strncmp,p,"$aux",4)==0 && type!=DYNAMIC);
top->cp =CP;
top->e =E;
top->b =B;
top->invoc_nb =invoc_nb++;
top->indice_nb =indice_nb;
if (type!=DYNAMIC)
{
if (top->arity>0)
{
top->x.f_n=Functor_Arity(top->atom,top->arity);
top->word=Tag_Value(STC,&(top->x.f_n));
adr=(WamWord *) (top+1);
for(i=0;i<top->arity;i++)
*adr++ = X(i);
}
else
top->word=Tag_Value(CST,top->atom);
}
else
{
Y_Storing_Invoc_Nb(E)=top->invoc_nb; /* see call.{pl,usr} */
top->word=A(0);
top->x.first_clause=TRUE;
}
top_stack=top_env=top;
catch_fail=FALSE;
redo=FALSE;
Read_Command(CALL,TRUE,NULL);
}
/*-------------------------------------------------------------------------*/
/* EXIT_PORT */
/* */
/*-------------------------------------------------------------------------*/
static void Exit_Port(Bool from_dynamic)
{
Bool last;
int dyn_invoc_nb;
redo=FALSE;
if (!from_dynamic)
while(top_env>debug_stack && top_env->cp==CP && top_env->e==E)
{
Read_Command(EXIT,TRUE,NULL);
top_env=top_env->caller_env;
}
else
{
dyn_invoc_nb=Y_Storing_Invoc_Nb(E);
do
{
Read_Command(EXIT,TRUE,NULL);
last=(top_env->invoc_nb==dyn_invoc_nb);
top_env=top_env->caller_env;
}
while(!last);
}
}
/*-------------------------------------------------------------------------*/
/* FAIL_PORT */
/* */
/*-------------------------------------------------------------------------*/
static void Fail_Port(void)
{
RunInf *top_bkt;
top_bkt=Find_Non_Determin_Env(top_stack,B);
if (top_bkt==debug_stack)
top_bkt=top_env;
if (top_bkt==debug_stack)
{
Lib1(printf,"Not enough debug information at Fail Port\n");
return;
}
redo=TRUE;
while(top_env>debug_stack && top_env>=top_bkt)
{
Read_Command(FAIL,TRUE,NULL);
top_env=top_env->caller_env;
}
top_env=top_bkt;
invoc_nb=top_env->invoc_nb+1;
}
/*-------------------------------------------------------------------------*/
/* REDO_PORT */
/* */
/*-------------------------------------------------------------------------*/
static void Redo_Port(void)
{
redo=FALSE;
Read_Command(REDO,TRUE,NULL);
}
/*-------------------------------------------------------------------------*/
/* READ_COMMAND */
/* */
/*-------------------------------------------------------------------------*/
static void Read_Command(int port,Bool read_cmd,char *str_next_inst)
{
FctPtr command;
char c_spy;
Bool disp_full_term;
char *port_name;
char str[80];
long key;
if (debug_mode==atom_nodebug || wam_curr_inst<wam_next_inst)
return;
key=Functor_Arity(top_env->atom,top_env->arity);
c_spy=(Hash_Fast_Find_Int(spy_tbl,key)) ? '+' : ' ';
if (leap_mode && c_spy==' ')
return;
if (skip_invoc_nb>0) /* skip */
{
if (top_env->invoc_nb!=skip_invoc_nb)
return;
if (port!=EXIT && (port!=FAIL || B>top_env->b))
return;
}
if (!exact_trace && top_env->aux_pred)
return;
if (read_cmd && port!=WAMI &&
!(leash_option & port) && !leap_mode && skip_invoc_nb==0)
read_cmd=FALSE;
leap_mode =FALSE;
skip_invoc_nb=0;
wam_next_inst=0;
switch(port)
{
case CALL:
port_name="Call";
disp_full_term=TRUE;
break;
case EXIT:
port_name="Exit";
disp_full_term=TRUE;
break;
case FAIL:
port_name="Fail";
/* disp_full_term=TRUE; */
disp_full_term=(top_env->type!=DYNAMIC);
break;
case REDO:
port_name="Redo";
disp_full_term=(exact_trace && top_env->type!=EXTERNAL);
break;
}
if (port!=WAMI)
{
Lib5(printf," %c %4d %4d %s: ",c_spy,top_env->invoc_nb,
top_env->indice_nb,port_name);
if (top_env->type==EXTERNAL)
Lib1(printf,"(external) ");
if (disp_full_term)
Complex_Write_Term(stdout,depth,FALSE,TRUE,TRUE,top_env->word);
else
Lib3(printf,"%s/%d",top_env->atom->name,top_env->arity);
}
else
Lib3(printf,"Wam Inst. (%5d) : %s",wam_curr_inst,str_next_inst);
if (!read_cmd)
{
Lib1(printf,"\n");
return;
}
Lib1(printf," ? ");
*str='\0';
Lib3(fgets,str,sizeof(str),stdin);
str[strlen(str)-1]='\0';
if (*str=='\0')
Lib2(strcpy,str,"creep");
Scan_Command(str);
if ((command=Find_Function())==NULL || !(*command)(port))
Read_Command(port,TRUE,str_next_inst);
}
/*-------------------------------------------------------------------------*/
/* SCAN_COMMAND */
/* */
/*-------------------------------------------------------------------------*/
static void Scan_Command(char *source_str)
{
char str[80];
char *p,*q;
Lib2(strcpy,str,source_str);
nb_read_arg=0;
p=(char *) Lib2(strtok,str,SEPARATOR_LIST);
while(p)
{
q=p;
p=(char *) Lib2(strtok,NULL,SEPARATOR_LIST);
Lib2(strcpy,read_arg[nb_read_arg++],q);
}
}
/*-------------------------------------------------------------------------*/
/* FIND_FUNCTION */
/* */
/*-------------------------------------------------------------------------*/
static FctPtr Find_Function(void)
{
int lg;
int i;
static
InfCmd cmd[]= { { "creep", Creep },
{ "skip", Skip },
{ "leap", Leap },
{ "abort", Abort },
{ "goalsb", Goals_GoalsB },
{ "gb", Goals_GoalsB },
{ "leash", Leash },
{ "nodebug", NoDebug },
{ "notrace", NoDebug },
{ "=", Debugging },
{ "+", Spy_NoSpy_NoSpyAll },
{ "-", Spy_NoSpy_NoSpyAll },
{ "@", Exec_Prolog_Goal },
{ "<", Depth },
{ "exact", Exact_NoExact },
{ "noexact", Exact_NoExact },
{ "write", Write_Data_Modify },
{ "data", Write_Data_Modify },
{ "modify", Write_Data_Modify },
{ "where", Where },
{ "deref", Dereference },
{ "envir", Environment },
{ "backtrack", Backtrack },
{ "instruction", Instruction },
{ "help", Help }
};
if (nb_read_arg==0)
return NULL;
lg=Lib1(strlen,read_arg[0]);
for(i=0;i<sizeof(cmd)/sizeof(InfCmd);i++)
if (Lib3(strncmp,cmd[i].name,read_arg[0],lg)==0)
return cmd[i].fct;
Lib1(printf,"Unknown command - try help\n");
return NULL;
}
/*-------------------------------------------------------------------------*/
/* CREEP */
/* */
/*-------------------------------------------------------------------------*/
static Bool Creep(void)
{
return TRUE;
}
/*-------------------------------------------------------------------------*/
/* SKIP */
/* */
/*-------------------------------------------------------------------------*/
static Bool Skip(int port)
{
RunInf *top=top_env;
int invoc;
invoc=(nb_read_arg==1) ? top->invoc_nb : Lib1(atoi,read_arg[1]);
if (invoc==top->invoc_nb && (port==EXIT || port==FAIL) &&
invoc==top->invoc_nb)
{
Lib1(printf,"Option not applicable at this port\n");
return FALSE;
}
if (invoc<top->invoc_nb)
{
while(top>debug_stack && top->invoc_nb>invoc)
top=top->caller_env;
if (top->invoc_nb!=invoc)
{
Lib1(printf,"Incorrect invocation number (try goals)\n");
return FALSE;
}
Lib1(printf,"Skip backward\n");
}
else
if (invoc>top->invoc_nb)
Lib1(printf,"Skip forward\n");
skip_invoc_nb=invoc;
return TRUE;
}
/*-------------------------------------------------------------------------*/
/* LEAP */
/* */
/*-------------------------------------------------------------------------*/
static Bool Leap(void)
{
leap_mode=TRUE;
return TRUE;
}
/*-------------------------------------------------------------------------*/
/* ABORT */
/* */
/*-------------------------------------------------------------------------*/
static Bool Abort(void)
{
Prototype(Prefix(Pred_Name(ABORT,0)))
Execute_A_Continuation((CodePtr) Prefix(Pred_Name(ABORT,0)));
}
/*-------------------------------------------------------------------------*/
/* GOALS_GOALSB */
/* */
/*-------------------------------------------------------------------------*/
static Bool Goals_GoalsB(void)
{
int nb= -1;
if (nb_read_arg>1)
nb=Lib1(atoi,read_arg[1]);
Lib1(printf,"Ancestors:\n");
if (Lib2(strchr,read_arg[0],'b')==NULL)
One_Goal(nb,NULL,top_env,NULL);
else
One_Goal(nb,Find_Non_Determin_Env(top_stack,B),top_env,B);
Lib1(printf,"\n");
return FALSE;
}
/*-------------------------------------------------------------------------*/
/* ONE_GOAL */
/* */
/*-------------------------------------------------------------------------*/
static void One_Goal(int nb,RunInf *top_bkt_e,RunInf *top_caller_e,
WamWord *b)
{
RunInf *top;
int nb_chc_pnt=0;
Bool disp_env;
top=math_max(top_bkt_e,top_caller_e);
if (top==debug_stack || nb==0)
return;
while(b>top->b)
{
b=(WamWord *) BB(b);
nb_chc_pnt++;
}
if (top==top_bkt_e)
top_bkt_e=Find_Non_Determin_Env(top_bkt_e,b);
if (top==top_caller_e)
{
disp_env=TRUE;
top_caller_e=top->caller_env;
}
else
disp_env=FALSE;
One_Goal(--nb,top_bkt_e,top_caller_e,b);
if (!exact_trace && top->aux_pred)
return;
if (nb_chc_pnt==0)
Lib1(printf," ");
else
Lib2(printf,"%2d ",nb_chc_pnt);
Lib3(printf,"%4d %4d ",top->invoc_nb,top->indice_nb);
if (disp_env)
Complex_Write_Term(stdout,depth,FALSE,TRUE,TRUE,top->word);
else
Lib3(printf," %s/%d",top->atom->name,top->arity);
Lib1(printf,"\n");
}
/*-------------------------------------------------------------------------*/
/* LEASH */
/* */
/*-------------------------------------------------------------------------*/
static Bool Leash(void)
{
int i;
Debug_Add_Leash_Mode(NULL);
for(i=1;i<nb_read_arg;i++)
switch(*read_arg[i])
{
case 'c':
Debug_Add_Leash_Mode(atom_call);
break;
case 'e':
Debug_Add_Leash_Mode(atom_exit);
break;
case 'f':
Debug_Add_Leash_Mode(atom_fail);
break;
case 'r':
Debug_Add_Leash_Mode(atom_redo);
break;
}
Debug_Display_Leashing();
return FALSE;
}
/*-------------------------------------------------------------------------*/
/* DEBUG_ADD_LEASH_MODE */
/* */
/*-------------------------------------------------------------------------*/
Bool Debug_Add_Leash_Mode(AtomInf *leash_mode)
{
if (leash_mode==NULL)
{
leash_option=0;
return TRUE;
}
if (leash_mode==atom_call)
{
leash_option|=CALL;
return TRUE;
}
if (leash_mode==atom_exit)
{
leash_option|=EXIT;
return TRUE;
}
if (leash_mode==atom_fail)
{
leash_option|=FAIL;
return TRUE;
}
if (leash_mode==atom_redo)
{
leash_option|=REDO;
return TRUE;
}
return FALSE;
}
/*-------------------------------------------------------------------------*/
/* NODEBUG */
/* */
/*-------------------------------------------------------------------------*/
static Bool NoDebug(void)
{
Debug_Set_Mode(atom_nodebug);
return TRUE;
}
/*-------------------------------------------------------------------------*/
/* DEBUGGING */
/* */
/*-------------------------------------------------------------------------*/
static Bool Debugging(void)
{
Debug_Display_Infos();
return FALSE;
}
/*-------------------------------------------------------------------------*/
/* DEBUG_DISPLAY_INFOS */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Display_Infos(void)
{
WamWord *pkey;
int nb_spy=0;
AtomInf *atom;
int arity;
Debug_Display_Mode();
Debug_Display_Leashing();
Debug_Display_Exact();
pkey=(WamWord *) Hash_Lookup(spy_tbl,NULL,H_NEXT);
while(pkey)
{
if (nb_spy++ == 0)
Lib1(printf,"Spypoints:\n");
atom=Functor_Of(*pkey);
arity=Arity_Of(*pkey);
Lib3(printf," %s/%d\n",atom->name,arity);
pkey=(WamWord *) Hash_Lookup(spy_tbl,(char *) pkey,H_NEXT);
}
if (nb_spy==0)
Lib1(printf,"There are no spypoints\n");
Lib1(printf,"\n");
}
/*-------------------------------------------------------------------------*/
/* DEBUG_DISPLAY_MODE */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Display_Mode(void)
{
char *s;
if (debug_mode==atom_debug)
s="The debugger will first leap -- showing spypoints (debug)\n";
if (debug_mode==atom_trace)
s="The debugger will first creep -- showing everything (trace)\n";
if (debug_mode==atom_nodebug)
s="The debugger is switched off\n";
Lib1(printf,s);
}
/*-------------------------------------------------------------------------*/
/* DEBUG_DISPLAY_LEASHING */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Display_Leashing(void)
{
Bool first=TRUE;
if (leash_option==0)
Lib1(printf,"No leashing\n");
else
{
Lib1(printf,"Using leashing stopping at ");
first=TRUE;
if (leash_option & CALL)
Lib2(printf,"%ccall",first ? '[' : ','), first=FALSE;
if (leash_option & EXIT)
Lib2(printf,"%cexit",first ? '[' : ','), first=FALSE;
if (leash_option & FAIL)
Lib2(printf,"%cfail",first ? '[' : ','), first=FALSE;
if (leash_option & REDO)
Lib2(printf,"%credo",first ? '[' : ','), first=FALSE;
Lib1(printf,"] ports\n");
}
}
/*-------------------------------------------------------------------------*/
/* DEBUG_DISPLAY_EXACT */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Display_Exact(void)
{
if (exact_trace)
Lib1(printf,"trace: exact (showing all visible failures)\n");
else
Lib1(printf,"trace: noexact (not showing failures when unifying heads)\n");
}
/*-------------------------------------------------------------------------*/
/* SPY_NOSPY_NOSPYALL */
/* */
/*-------------------------------------------------------------------------*/
static Bool Spy_NoSpy_NoSpyAll(void)
{
AtomInf *atom;
int arity;
char *p;
int i;
void (*f)();
if (nb_read_arg==2 && Lib2(strcmp,read_arg[1],"all")==0)
Debug_Remove_Spy_Point(NULL,0);
else
{
f=(*read_arg[0]=='+' ) ? Debug_Add_Spy_Point : Debug_Remove_Spy_Point;
if (nb_read_arg==1)
(*f)(top_env->atom,top_env->arity);
else
for(i=1;i<nb_read_arg;i++)
{
p=(char *) Lib2(strchr,read_arg[i],'/');
if (!p)
Lib2(printf,"arity missing for %s\n",read_arg[i]);
else
{
*p='\0';
arity=Lib1(atoi,p+1);
atom=Create_Allocate_Atom(read_arg[i]);
(*f)(atom,arity);
}
}
}
return FALSE;
}
/*-------------------------------------------------------------------------*/
/* DEBUG_ADD_SPY_POINT */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Add_Spy_Point(AtomInf *atom,int arity)
{
long key=Functor_Arity(atom,arity);
char *s;
if (Hash_Lookup(spy_tbl,(char *) &key,H_CREATE))
s="Spypoint placed on %s/%d\n";
else
s="There already is a spypoint on %s/%d\n";
Lib3(printf,s,atom->name,arity);
}
/*-------------------------------------------------------------------------*/
/* DEBUG_REMOVE_SPY_POINT */
/* */
/*-------------------------------------------------------------------------*/
void Debug_Remove_Spy_Point(AtomInf *atom,int arity)
{
long key=Functor_Arity(atom,arity);
char *s;
if (atom==NULL) /* for builtin nospyall/0 in trace.pl */
{
Hash_Delete_All(spy_tbl);
Lib1(printf,"All spypoints removed\n");
return;
}
if (Hash_Lookup(spy_tbl,(char *) &key,H_DELETE))
s="Spypoint removed from %s/%d\n";
else
s="There is no spypoint on %s/%d\n";
Lib3(printf,s,atom->name,arity);
}
/*-------------------------------------------------------------------------*/
/* EXEC_PROLOG_GOAL */
/* */
/*-------------------------------------------------------------------------*/
static Bool Exec_Prolog_Goal(void)
{
Prototype(Prefix(Pred_Name(DBG_EXEC,0)))
AtomInf *save_debug_mode=debug_mode;
WamWord *save_reg_bank=reg_bank;
WamWord local_reg_bank[REG_BANK_SIZE];
Switch_Reg_Bank(local_reg_bank);
debug_mode=atom_nodebug;
Call_Prolog((CodePtr) Prefix(Pred_Name(DBG_EXEC,0)));
debug_mode=save_debug_mode;
Switch_Reg_Bank(save_reg_bank);
return FALSE;
}
/*-------------------------------------------------------------------------*/
/* DEPTH */
/* */
/*-------------------------------------------------------------------------*/
static Bool Depth(void)
{
if (nb_read_arg==1)
depth=10;
else
depth=Lib1(atoi,read_arg[1]);
return FALSE;
}
/*-------------------------------------------------------------------------*/
/* EXACT_NOEXACT */
/* */
/*-------------------------------------------------------------------------*/
static Bool Exact_NoExact(void)
{
exact_trace= *read_arg[0]=='e';
Debug_Display_Exact();
return FALSE;
}
/*-------------------------------------------------------------------------*/
/* WRITE_DATA_MODIFY */
/* */
/*-------------------------------------------------------------------------*/
static Bool Write_Data_Modify(void)
{
WamWord *adr;
char *bank_name;
int offset;
int nb;
int i;
if (adr=Read_Bank_Adr(FALSE,1,&bank_name))
{
offset=(nb_read_arg<3) ? 0 : Read_Integer(2);
nb =(nb_read_arg<4) ? 1 : Read_Integer(3);
if (adr==reg_copy)
{
if (offset>=NB_OF_REGS)
offset=0;
if (nb_read_arg<4 && *read_arg[0]!='m')
nb=NB_OF_REGS-offset;
else
if (nb>NB_OF_REGS-offset)
nb=NB_OF_REGS-offset;
}
while(nb--)
{
Print_Bank_Name_Offset((adr==reg_copy) ? reg_tbl[offset] : "",
bank_name,offset);
Lib1(printf,":");
if (*read_arg[0]=='w')
Complex_Write_Term(stdout,depth,FALSE,TRUE,TRUE,adr[offset]);
else
{
Print_Wam_Word(adr+offset);
if (*read_arg[0]=='m')
Modify_Wam_Word(adr+offset);
}
Lib1(printf,"\n");
offset++;
}
}
if (adr==reg_copy) /* saved by Read_Bank_Adr */
for(i=0;i<NB_OF_REGS;i++)
Reg(i)=reg_copy[i];
return FALSE;
}
/*-------------------------------------------------------------------------*/
/* WHERE */
/* */
/*-------------------------------------------------------------------------*/
static Bool Where(void)
{
char *stack_name;
int offset;
WamWord word,tag,*adr;
if (adr=Read_Bank_Adr(TRUE,1,&stack_name))
{
offset=(nb_read_arg<3) ? 0 : Read_Integer(2);
Print_Bank_Name_Offset((adr==reg_copy) ? reg_tbl[offset] : "",
stack_name,offset);
Lib2(printf," at %#lx\n",adr+offset);
}
return FALSE;
}
/*-------------------------------------------------------------------------*/
/* DEREFERENCE */
/* */
/*-------------------------------------------------------------------------*/
static Bool Dereference(void)
{
char *bank_name;
char *stack_name;
int offset;
WamWord word,tag,*adr;
WamWord *d_adr;
if (adr=Read_Bank_Adr(FALSE,1,&bank_name))
{
offset=(nb_read_arg<3) ? 0 : Read_Integer(2);
Deref(adr[offset],word,tag,d_adr);
Print_Bank_Name_Offset((adr==reg_copy) ? reg_tbl[offset] : "",
bank_name,offset);
Lib1(printf,":");
if (adr=Detect_Stack(d_adr,&stack_name))
{
Lib1(printf," --> \n");
Print_Bank_Name_Offset("",stack_name,d_adr-adr);
Lib1(printf,":");
}
Print_Wam_Word(d_adr);
Lib1(printf,"\n");
}
return FALSE;
}
/*-------------------------------------------------------------------------*/
/* ENVIRONMENT */
/* */
/*-------------------------------------------------------------------------*/
static Bool Environment(void)
{
WamWord *adr;
int offset;
char *stack_name;
int i;
if (nb_read_arg==1)
{
adr=Detect_Stack(E,&stack_name);
offset=E-adr;
adr=E;
}
else
{
if ((adr=Read_Bank_Adr(TRUE,1,&stack_name))==NULL)
return FALSE;
offset=(nb_read_arg<3) ? 0 : Read_Integer(2);
adr+=offset;
}
for(i=ENVIR_STATIC_SIZE;i>0;i--)
{
Print_Bank_Name_Offset(envir_name[i-1],stack_name,offset-i);
Lib1(printf,":");
Print_Wam_Word(adr-i);
Lib1(printf,"\n");
}
return FALSE;
}
/*-------------------------------------------------------------------------*/
/* BACKTRACK */
/* */
/*-------------------------------------------------------------------------*/
static Bool Backtrack(void)
{
WamWord *adr;
int offset;
char *stack_name;
int i;
if (nb_read_arg==1)
{
adr=Detect_Stack(B,&stack_name);
offset=B-adr;
adr=B;
}
else
{
if ((adr=Read_Bank_Adr(TRUE,1,&stack_name))==NULL)
return FALSE;
offset=(nb_read_arg<3) ? 0 : Read_Integer(2);
adr+=offset;
}
for(i=CHOICE_STATIC_SIZE;i>0;i--)
{
Print_Bank_Name_Offset(choice_name[i-1],stack_name,offset-i);
Lib1(printf,":");
Print_Wam_Word(adr-i);
Lib1(printf,"\n");
}
return FALSE;
}
/*-------------------------------------------------------------------------*/
/* READ_BANK_ADR */
/* */
/*-------------------------------------------------------------------------*/
static WamWord *Read_Bank_Adr(Bool only_stack,int arg_nb,char **bank_name)
{
int lg;
int offset;
int i;
if (nb_read_arg<arg_nb+1)
{
Lib2(printf,"%s name expected\n",(only_stack) ? "Stack" : "Bank");
return NULL;
}
lg=Lib1(strlen,read_arg[arg_nb]);
if (!only_stack)
{
if (read_arg[arg_nb][0]=='x' && lg==1)
{
*bank_name="x";
return &X(0);
}
if (read_arg[arg_nb][0]=='y' && lg==1)
{
*bank_name="y";
return &Y(E,0);
}
if (Lib3(strncmp,"reg",read_arg[arg_nb],lg)==0)
{
*bank_name="reg";
for(i=0;i<NB_OF_REGS;i++)
reg_copy[i]=Reg(i);
return reg_copy;
}
}
for(i=0;i<NB_OF_STACKS;i++)
if (Lib3(strncmp,stk_tbl[i].name,read_arg[arg_nb],lg)==0)
{
*bank_name=stk_tbl[i].name;
return stk_tbl[i].stack;
}
Lib2(printf,"Incorrect %s name\n",(only_stack) ? "stack" : "bank");
return NULL;
}
/*-------------------------------------------------------------------------*/
/* READ_INTEGER */
/* */
/*-------------------------------------------------------------------------*/
static int Read_Integer(int arg_nb)
{
char *p;
int val=0;
val=Lib3(strtol,read_arg[arg_nb],&p,0);
if (*p)
Lib1(printf,"Incorrect integer\n");
return val;
}
/*-------------------------------------------------------------------------*/
/* PRINT_BANK_NAME_OFFSET */
/* */
/*-------------------------------------------------------------------------*/
static void Print_Bank_Name_Offset(char *prefix,char *bank_name,int offset)
{
char str[80];
int lg=Lib1(strlen,prefix);
if (lg)
Lib2(printf,"%s",prefix);
Lib4(sprintf,str,"%s[%d]",bank_name,offset);
lg+=Lib1(strlen,str);
if (lg>BANK_NAME_OFFSET_LENGTH)
lg=BANK_NAME_OFFSET_LENGTH-1;
Lib4(printf,"%*s%s",BANK_NAME_OFFSET_LENGTH-lg,"",str);
}
/*-------------------------------------------------------------------------*/
/* PRINT_WAM_WORD */
/* */
/*-------------------------------------------------------------------------*/
static void Print_Wam_Word(WamWord *word_adr)
{
WamWord word= *word_adr;
WamWord tag;
WamWord value;
char *stack_name;
WamWord *adr;
AtomInf *functor;
int arity;
Lib5(printf,"%#*lx %*ld ",HEXADECIMAL_LENGTH,(long) word,
DECIMAL_LENGTH, (long) word);
if (adr=Detect_Stack((WamWord *) word,&stack_name))
Print_Bank_Name_Offset("",stack_name,(WamWord *) word-adr);
else
Lib3(printf,"%*s",BANK_NAME_OFFSET_LENGTH,"?[?]");
Lib1(printf," ");
tag=Tag_Of(word);
if (tag<NB_OF_TAGS)
{
switch(tag_tbl[tag].type)
{
case INTEGER:
value=(WamWord) UnTag_Integer(word);
Lib4(printf,"%s,%*ld",tag_tbl[tag].name,
VALUE_PART_LENGTH,(long) value);
break;
case UNSIGNED:
value=(WamWord) UnTag_Unsigned(word);
Lib4(printf,"%s,%*lu",tag_tbl[tag].name,
VALUE_PART_LENGTH,(long) value);
break;
case STACK:
value=(WamWord) UnTag_Stack(word);
if (adr=Detect_Stack((WamWord *) value,&stack_name))
{
Lib2(printf,"%s,",tag_tbl[tag].name);
Print_Bank_Name_Offset("",stack_name,(WamWord *) value-adr);
}
else
tag= -1;
break;
case MALLOC:
value=(WamWord) UnTag_Malloc(word);
if (Hash_Is_An_Element(atom_tbl,(char *) value))
Lib4(printf,"%s,%*s",tag_tbl[tag].name,
VALUE_PART_LENGTH,((AtomInf *)value)->name);
else
Lib4(printf,"%s,%#*lx",tag_tbl[tag].name,
VALUE_PART_LENGTH,(long) value);
break;
}
}
else
tag= -1;
if (tag== -1)
Lib3(printf,"???,%*s",VALUE_PART_LENGTH,"?");
Lib1(printf," ");
if (word_adr>=Trail_Stack && word_adr<Trail_Stack+Trail_Size)
{
tag =Trail_Tag_Of(word);
value=Trail_Value_Of(word);
if (tag==TFC)
Lib4(printf,"%s,%#*lx",trail_tag_name[tag],
VALUE_PART_LENGTH,(long) value);
else
if (tag<NB_OF_TRAIL_TAGS &&
(adr=Detect_Stack((WamWord *) value,&stack_name))!=NULL &&
*stack_name!='t')
{
Lib2(printf,"%s,",trail_tag_name[tag]);
Print_Bank_Name_Offset("",stack_name,(WamWord *) value-adr);
}
else
Lib3(printf,"???,%*s",VALUE_PART_LENGTH,"?");
Lib1(printf," ");
}
functor=Functor_Of(word);
arity =Arity_Of(word);
if (Hash_Is_An_Element(atom_tbl,(char *) functor) &&
arity>=0 && arity<=MAX_ARITY)
Lib3(printf,"%12s/%-3d",functor->name,arity);
}
/*-------------------------------------------------------------------------*/
/* MODIFY_WAM_WORD */
/* */
/*-------------------------------------------------------------------------*/
static void Modify_Wam_Word(WamWord *word_adr)
{
WamWord word;
char *bank_name;
WamWord *adr;
int offset;
char str[80];
char *comma;
char *slash;
char *p;
int i;
for(;;)
{
Lib1(printf,"\nNew value: ");
*str='\0';
Lib3(fgets,str,sizeof(str),stdin);
str[strlen(str)-1]='\0';
if (*str=='\0')
return;
Scan_Command(str);
if (comma=(char *) Lib2(strchr,str,','))
goto tag_value;
if (slash=(char *) Lib2(strchr,read_arg[0],'/'))
goto functor_arity;
integer:
if (nb_read_arg==1 && *read_arg[0]>='0' && *read_arg[0]<='9')
{
word=Lib3(strtol,read_arg[0],&p,0);
if (*p=='\0')
{
*word_adr=word;
return;
}
else
goto err;
}
stack_adr:
if (adr=Read_Bank_Adr(TRUE,0,&bank_name))
{
offset=(nb_read_arg<2) ? 0 : Read_Integer(1);
*word_adr=(WamWord) (adr+offset);
return;
}
goto err;
tag_value:
comma++;
for(i=0;i<NB_OF_TAGS;i++)
if (Lib2(strcmp,tag_tbl[i].name,read_arg[0])==0)
break;
if (i<NB_OF_TAGS)
{
switch(tag_tbl[i].type)
{
case INTEGER:
case UNSIGNED:
*word_adr=Tag_Value(i,Read_Integer(1));
return;
case STACK:
if (adr=Read_Bank_Adr(TRUE,1,&bank_name))
{
offset=(nb_read_arg<3) ? 0 : Read_Integer(2);
*word_adr=Tag_Value(i,adr+offset);
return;
}
goto err;
case MALLOC:
word=Lib3(strtol,comma,&p,0);
if (*p=='\0')
{
*word_adr=Tag_Value(i,word);
return;
}
else
if (Lib2(strcmp,read_arg[0],"CST")==0)
{
*word_adr=Tag_Value(i,Create_Allocate_Atom(comma));
return;
}
goto err;
}
}
trail_tag_value:
for(i=0;i<NB_OF_TRAIL_TAGS;i++)
if (Lib2(strcmp,trail_tag_name[i],read_arg[0])==0)
if (adr=Read_Bank_Adr(TRUE,1,&bank_name))
{
offset=(nb_read_arg<3) ? 0 : Read_Integer(2);
*word_adr=Trail_Tag_Value(i,adr+offset);
return;
}
goto err;
functor_arity:
*slash='\0';
i=Lib3(strtol,slash+1,&p,0);
if (*p!='\0' || i<1 || i>MAX_ARITY)
goto err;
word=Lib3(strtol,read_arg[0],&p,0);
if (*p!='\0')
word=(long) Create_Allocate_Atom(read_arg[0]);
else
if (!Hash_Is_An_Element(atom_tbl,(char *) word))
goto err;
*word_adr=Functor_Arity(word,i);
Lib3(printf,"--> %s/%d",((AtomInf *) word)->name,i);
return;
err:
Lib1(printf,"Error...");
}
}
/*-------------------------------------------------------------------------*/
/* DETECT_STACK */
/* */
/*-------------------------------------------------------------------------*/
static WamWord *Detect_Stack(WamWord *adr,char **stack_name)
{
int i;
for(i=0;i<NB_OF_STACKS;i++)
if (adr>=stk_tbl[i].stack && adr<stk_tbl[i].stack+stk_tbl[i].size)
{
*stack_name=stk_tbl[i].name;
return stk_tbl[i].stack;
}
return NULL;
}
/*-------------------------------------------------------------------------*/
/* INSTRUCTION */
/* */
/*-------------------------------------------------------------------------*/
static Bool Instruction(void)
{
wam_next_inst=(nb_read_arg==1) ? wam_curr_inst+1 : Read_Integer(1);
return TRUE;
}
/*-------------------------------------------------------------------------*/
/* HELP */
/* */
/*-------------------------------------------------------------------------*/
static Bool Help(void)
{
int i;
#define L(str) Lib2(printf,"%s\n",str);
L("Prolog level")
L("")
L("creep or ENTER single-step to the very next port")
L("skip <n> skip and stop at return of the <n> invocated pred")
L("leap resume running (only stopping on spy-points)")
L("abort abort the current execution")
L("goals <n> print <n> ancestor goals")
L("goalsb <n> print <n> ancestor goals and choice points")
L("leash <l>... set the leashing mode to <l> (call/exit/fail/redo)")
L("nodebug switch the debugger off")
L("notrace equivalent to nodebug")
L("= output information concerning the debugger")
L("+ <f/n>... place a spy-point on each <f/n> (or current)")
L("- <f/n>... remove spy-point on each <f/n> (or current)")
L("@ call arbitrary Prolog goal")
L("< <n> set the print depth limit to <n> (or reset)")
L("exact trace all failures (and auxiliary predicates)")
L("noexact do not trace fail when unifying the head")
L("")
L("Wam level")
L("")
L("write adr <n> write <n> Prolog terms starting at <adr>")
L("data adr <n> display <n> words starting at <adr>")
L("modify adr <n> display and modify <n> words starting at <adr>")
L("where sadr display the exact address corresponding to <sadr>")
L("deref adr display the dereferenced word started at <adr>")
L("envir <sadr> display an environment located at <sadr> (or current)")
L("backtrack <sadr> display a choice point located at <sadr> (or current)")
L("instruction <n> execute one instruction or until instruction <n>")
L("")
L("An address (adr) has the following syntax: bank_name < [n] >")
L(" bank_name is either reg/x/y/stack_name (see below)")
L(" n is an optional offset specifier (Integer)")
L("")
L("A stack address (sadr) has the following syntax: stack_name < [n] >")
Lib1(printf," stack_name is either");
for(i=0;i<NB_OF_STACKS;i++)
Lib2(printf," %s",stk_tbl[i].name);
Lib1(printf,"\n\n");
return FALSE;
}
syntax highlighted by Code2HTML, v. 0.9.1