RPN32 - Ukázkový program rpn32.c
Instrukční sada •
Seznam instrukcí •
Funkce API •
Header •
Příklady •
Download
#include <stdio.h>
#include <ctype.h> // isspace
#include <limits.h> // CHAR_BIT
#include <stdarg.h> // va_*
#include <stdlib.h> // malloc, strtoul
#include <string.h> // strstr, strcpy, strlen
#include "rpn32.h"
/*============================================================================*\
VYSTUP / VYPIS
\*============================================================================*/
// Uvodni retezec vypisu hlaseni
//
static char const *reportprefixp = NULL;
/*
* VYPIS HLASENI A OSTATNICH RADEK TEXTU
*/
#define Outline(l) puts(l)
static int Report(char const *formatp, ...)
{
int numch;
va_list args;
if(reportprefixp != NULL)
for(numch = 0; reportprefixp[numch] != '\0'; ++numch)
putchar(reportprefixp[numch]);
va_start(args, formatp);
numch = vprintf(formatp, args);
va_end(args);
return(numch);
}
/*----------------------------------------------------------------------------*\
NAPOVEDA
\*----------------------------------------------------------------------------*/
// Rizeni vypisu - "default" hodnoty
//
#define DFLT_VIEW_MODE_LIST RPN32_VIEW_MODE_STR_ADDRESS
#define _DFLT_VIEW_MODE_TRACE RPN32_VIEW_MODE_STR_SGN \
RPN32_VIEW_MODE_STR_DEC \
RPN32_VIEW_MODE_STR_STACK \
RPN32_VIEW_MODE_STR_REG_LASTX
#define DFLT_VIEW_MODE_TRACE _DFLT_VIEW_MODE_TRACE \
RPN32_VIEW_MODE_STR_ADDRESS
#define DFLT_VIEW_MODE_RESULT _DFLT_VIEW_MODE_TRACE \
RPN32_VIEW_MODE_STR_LINE
// Retezec uvozujici komentar v programu
//
#define DFLT_LINE_COMMENT "#"
/*............................................................................*\
KOMPLETNI TEXTY
\*............................................................................*/
// "Options" na "command-line"
//
#define HELP_TEXT_OPTIONS \
"Use:\n" \
"# rpn32 [options] pl1 [pl2 [ ... plN]] [= [[[regT] regZ] regY] regX] [=]\n" \
"# rpn32 [options] filename [[[[regT] regZ] regY] regX] [=]\n" \
"\n" \
"Options:\n" \
"+--------+---------------------------------------------+------------------+\n" \
"| Option | Description | Default |\n" \
"+--------+---------------------------------------------+------------------+\n" \
"| -s<N> | Starting label | from begin |\n" \
"| -l[S] | LISTING alowed [mode] | suppressed [" DFLT_VIEW_MODE_LIST "] |\n"\
"| -L[S] | LISTING ONLY (executing suppressed) [mode] | suppressed [" DFLT_VIEW_MODE_LIST "] |\n"\
"| -u | MEMORY ussage (reg's, labels & RTN pool) | suppressed |\n" \
"| -U | MEMORY ussage ONLY (executing suppressed) | suppressed |\n" \
"| -m<S> | TRACE & PAUSE [mode] | [" DFLT_VIEW_MODE_TRACE "] |\n"\
"| -t | TRACE alowed | suppressed |\n" \
"| -r[S] | RESULT [mode] (none -> like TRACE & PAUSE) | [" DFLT_VIEW_MODE_RESULT "] |\n"\
"| -e<S> | Report prefix string | \"\" |\n"\
"| -c<S> | Comment string | \"" DFLT_LINE_COMMENT "\" |\n"\
"+--------+---------------------------------------------+------------------+\n"
// Argumenty na "command-line"
//
#define HELP_TEXT_ARGUMENTS \
"Arguments:\n" \
"+--------------------------+----------------------------------------------+\n" \
"| Argument | Description |\n" \
"+--------------------------+----------------------------------------------+\n" \
"| pl1, pl2, ... plN | Program lines (missing are read from stdin) |\n" \
"| filename | File of program lines (\"-\" -> stdin is used) |\n"\
"| = | End of program |\n" \
"| regX, regY, regZ, regT | Registers of RPN-stack (LCN alowed) |\n" \
"| = | Interactive mode (type \"hlp\" to learn more) |\n"\
"+--------------------------+----------------------------------------------+\n" \
"Loop Control Number (LCN) format: COUNTER,FINAL[,INCREMENT]\n"
// Znaky "formatovaciho retezce"
//
#define HELP_TEXT_MODE_FORMAT \
"Characters of MODE (outputs control):\n" \
"+------+-------------------------+------+---------------------------------+\n" \
"| Chr | Description | Chr | Description |\n" \
"+------+-------------------------+------+---------------------------------+\n" \
"| " RPN32_VIEW_MODE_STR_SGN " | Signed |" \
" " RPN32_VIEW_MODE_STR_REG_X RPN32_VIEW_MODE_STR_REG_Y RPN32_VIEW_MODE_STR_REG_Z RPN32_VIEW_MODE_STR_REG_T " | Registers of RPN-stack |\n"\
"| " RPN32_VIEW_MODE_STR_UNS " | Unsigned |" \
" " RPN32_VIEW_MODE_STR_STACK " | All registers of RPN-stack |\n" \
"| " RPN32_VIEW_MODE_STR_DEC " | Decimal |" \
" " RPN32_VIEW_MODE_STR_REG_LASTX " | LASTx register |\n" \
"| " RPN32_VIEW_MODE_STR_OCT " | Octal |" \
" " RPN32_VIEW_MODE_STR_FLAGS " | Flags |\n" \
"| " RPN32_VIEW_MODE_STR_HEX " | Hexadecimal |" \
" " RPN32_VIEW_MODE_STR_RTN " | RTN pool level |\n" \
"| " RPN32_VIEW_MODE_STR_INDIRECT " | Indirect |" \
" " RPN32_VIEW_MODE_STR_LOCNUM " | Local registers pool level |\n" \
"| " RPN32_VIEW_MODE_STR_LOCREG " | Local register |" \
" " RPN32_VIEW_MODE_STR_ADDRESS " | Address of program line |\n" \
"| " RPN32_VIEW_MODE_STR_SEPARATOR " | Separator reg. numbers |" \
" " RPN32_VIEW_MODE_STR_CODE " | Machine code |\n" \
"| " RPN32_VIEW_MODE_STR_COMPAT " | RPNPROC compatibility |" \
" " RPN32_VIEW_MODE_STR_USUAL " | Usual combination [" RPN32_VIEW_MODE_STR_MODE_USUAL "] |\n"\
"| " RPN32_VIEW_MODE_STR_ESCAPE " | Escape character |" \
" " RPN32_VIEW_MODE_STR_LINE " | Suppress program line mnemonics |\n" \
"| <N> | Memory register number |" \
" | Any other character is stored |\n" \
"+------+-------------------------+------+---------------------------------+\n"
// Priklady
//
#define HELP_TEXT_EXAMPLES_MODE_1 \
"-m" \
RPN32_VIEW_MODE_STR_UNS \
RPN32_VIEW_MODE_STR_HEX \
RPN32_VIEW_MODE_STR_REG_X \
RPN32_VIEW_MODE_STR_SGN \
RPN32_VIEW_MODE_STR_DEC \
RPN32_VIEW_MODE_STR_REG_X \
RPN32_VIEW_MODE_STR_UNS \
RPN32_VIEW_MODE_STR_HEX \
RPN32_VIEW_MODE_STR_REG_LASTX \
RPN32_VIEW_MODE_STR_SGN \
RPN32_VIEW_MODE_STR_DEC \
RPN32_VIEW_MODE_STR_REG_LASTX \
"0" \
RPN32_VIEW_MODE_STR_SEPARATOR \
"1" \
RPN32_VIEW_MODE_STR_INDIRECT "0" \
RPN32_VIEW_MODE_STR_INDIRECT "1" \
RPN32_VIEW_MODE_STR_ADDRESS
#define HELP_TEXT_EXAMPLES_MODE_2 \
"\"" \
"-m\\c\\o\\un\\t\\d\\own\\=0" \
RPN32_VIEW_MODE_STR_LINE \
"\""
//
#define HELP_TEXT_EXAMPLES \
"Examples:\n" \
"# rpn32 <example.rpn\n" \
"# rpn32 + \"*\" = 12 0xAD 077\n" \
"# rpn32 + x = 12 0xAD 077\n" \
"# rpn32 " HELP_TEXT_EXAMPLES_MODE_1 " -t example.rpn\n" \
"# rpn32 sto0 lbl0 rcl0 count pse isg0 gto0 = 4,18,2\n" \
"# rpn32 lcn sto0 lbl0 rcl0 count pse isg0 gto0 = 2 18 4\n" \
"# rpn32 " HELP_TEXT_EXAMPLES_MODE_2 " -r sto0 lbl0 pse dsz0 gto0 = 6\n" \
"# rpn32 example.rpn =\n" \
"# rpn32 + \"*\" = 12 0xAD 077 =\n" \
"# rpn32 =\n" \
"# rpn32 ?reg19 =\n" \
"# substi <battery.rpn | rpn32 -t -s20 - = 36\n"
// Interactivni mod
//
#define HELP_TEXT_INTERACTIVE \
"Interactive mode commands:\n" \
"+---------+---------------------------------------------------------------+\n" \
"| Command | Description |\n" \
"+---------+-------------------+-------------------------------------------+\n" \
"| hlp | HELP | This text |\n" \
"| lst[S] | LIST [mode] | List of loaded program |\n" \
"| mem | MEMORY usage | List of used reg's, labels & RTN pool |\n" \
"| spy[S] | SPY [mode] *) | Current state (registers, program line) |\n" \
"| sst[S] | SST [mode] *) | SINGLE STEP & start of SINGLE STEP mode |\n" \
"| cmd | COMMAND | End of SINGLE STEP mode |\n" \
"| run[S] | RUN [mode] *) | Run program from current program line |\n" \
"| mod<S> | MODE <mode> | Set or... |\n" \
"| mod | MODE | ...display default MODE |\n" \
"| bye | BYE | End of program |\n" \
"+---------+-------------------+-------------------------------------------+\n" \
" *) MODE: <none> .... default MODE,\n" \
" <-> ....... inhibit,\n" \
" <+> ....... by command-line option \"-m\".\n"
/*============================================================================*\
SPOLECNE
\*============================================================================*/
// Znaky jednotlivych "options" na "command-line"
//
#define OPTCHAR_1ST '-'
//
#define OPTCHAR_START 's'
#define OPTCHAR_LSTONLY 'L'
#define OPTCHAR_LIST 'l'
#define OPTCHAR_MEMONLY 'U'
#define OPTCHAR_MEMUSAGE 'u'
#define OPTCHAR_MODE 'm'
#define OPTCHAR_TRACE 't'
#define OPTCHAR_RESULT 'r'
#define OPTCHAR_REPORT 'e'
#define OPTCHAR_COMMENT 'c'
#define OPTCHAR_HELP 'h'
//
#define OPTARGP(a) (*(a) + 2)
//
static char const *optmodelstp = DFLT_VIEW_MODE_LIST,
*optmodetrcp = DFLT_VIEW_MODE_TRACE,
*optmoderesp = DFLT_VIEW_MODE_RESULT,
*optcommentp = DFLT_LINE_COMMENT;
// Handle vrstvy "rpn32"
//
static rpn32hndl_t hndp;
/*
* CALLBACKY PRO VYPIS
*/
static int cb_rpn32_view(char const *linep,
void *userdata)
{
Report("%s%s\n", (char *)userdata, linep);
return(RPN32_RTNVAL_DONE);
}
static int cb_rpn32_listmem(char const *linep,
void *userdata)
{
userdata = userdata;
Outline(linep);
return(RPN32_RTNVAL_DONE);
}
/*
* TEXTOVA FORMA NAVRATOVE HODNOTY
*/
#define _RTNVAL_TEXT_IMOP "Immediate operand"
#define _RTNVAL_TEXT_NUMBER "Number of operands"
#define _RTNVAL_TEXT_OPERAND "Bad operand"
#define _RTNVAL_TEXT_LBLDUP "Label duplicated"
#define _RTNVAL_TEXT_MEMREQ "Memory request"
#define _RTNVAL_TEXT_MEMORY "Memory allocate"
#define _RTNVAL_TEXT_LBLOVF "Label # overflow"
#define _RTNVAL_TEXT_LBLNEX "Label nonexistent"
#define _RTNVAL_TEXT_ILLEGAL "Illegal instruction"
#define _RTNVAL_TEXT_REGOVF "Register # overflow"
#define _RTNVAL_TEXT_RTNOVF "Return stack overflow"
#define _RTNVAL_TEXT_DIVBY0 "Divide by zero"
#define _RTNVAL_TEXT_INVALID "Invalid data"
static char const *rtnval_text(int rtnval)
{
static char const *texpt[] = {RPN32_RTNVAL_ERROR_LIST(_RTNVAL_TEXT)};
if(rtnval == RPN32_RTNVAL_STOP)
return("Break");
rtnval = RPN32_RTNVAL_ERROR_INDEX(rtnval);
if((unsigned)rtnval >= sizeof(texpt) / sizeof(*texpt))
return("(unknown)");
return(texpt[rtnval]);
}
/*============================================================================*\
INICIALIZACE
\*============================================================================*/
/*----------------------------------------------------------------------------*\
OPTIONS NA COMMAND-LINE
\*----------------------------------------------------------------------------*/
// Prompty vypisu
//
#define REPORT_PROMPT(t) #t "> "
#define REPORT_PROMPT_INIT REPORT_PROMPT(INI)
// Inicializacni hodnoty
//
#define INITOPT_FLAGS_LIST 001
#define INITOPT_FLAGS_EXEC 002
#define INITOPT_FLAGS_MEMUSAGE 010
//
struct initopts
{
unsigned flags; // "INITOPT_FLAGS_*"
int startlbl; // starting label
int runcbtype; // "RPN32_RUN_CB_TYPE_*"
};
/*
* CISLO NAVESTI
*/
static int init_options_startlbl(char const *argp)
{
int startlbl;
char *endp;
startlbl = strtoul(argp, &endp, 0);
if(endp != argp)
if(*endp == '\0')
return(startlbl);
return(-1);
}
/*
* VSTUPNI BOD
*/
static int init_options(int argc,
char *argv[],
struct initopts *initoptp)
{
#define RETURN_MISSING() \
if(*OPTARGP(argv) == '\0') \
return(Report(REPORT_PROMPT_INIT "Missing value: \"%s\"\n", *argv), -1)
while(--argc)
{
++argv;
if(argv[0][0] == OPTCHAR_1ST)
switch(argv[0][1])
{
case OPTCHAR_START:
initoptp->startlbl = init_options_startlbl(OPTARGP(argv));
if(initoptp->startlbl >= 0)
continue;
Report(REPORT_PROMPT_INIT "Bad value (label): \"%s\"\n",
OPTARGP(argv));
return(-1);
case OPTCHAR_LSTONLY:
initoptp->flags &= ~INITOPT_FLAGS_EXEC;
case OPTCHAR_LIST:
initoptp->flags |= INITOPT_FLAGS_LIST;
if(*OPTARGP(argv) != '\0')
optmodelstp = OPTARGP(argv);
continue;
case OPTCHAR_MEMONLY:
initoptp->flags &= ~INITOPT_FLAGS_EXEC;
case OPTCHAR_MEMUSAGE:
initoptp->flags |= INITOPT_FLAGS_MEMUSAGE;
continue;
case OPTCHAR_MODE:
if(*OPTARGP(argv) != '\0')
optmodetrcp = OPTARGP(argv);
continue;
case OPTCHAR_TRACE:
initoptp->flags |= INITOPT_FLAGS_EXEC;
initoptp->runcbtype = RPN32_RUN_CB_TYPE_TRACE;
continue;
case OPTCHAR_RESULT:
optmoderesp = OPTARGP(argv);
continue;
case OPTCHAR_REPORT:
reportprefixp = OPTARGP(argv);
continue;
case OPTCHAR_COMMENT:
RETURN_MISSING();
optcommentp = OPTARGP(argv);
continue;
case OPTCHAR_HELP:
puts(HELP_TEXT_OPTIONS);
puts(HELP_TEXT_ARGUMENTS);
puts(HELP_TEXT_MODE_FORMAT);
puts(HELP_TEXT_EXAMPLES);
return(-1);
}
break;
}
if(*optmoderesp == '\0')
optmoderesp = optmodetrcp;
return(argc);
#undef RETURN_MISSING
}
/*----------------------------------------------------------------------------*\
NACTENI RPN PROGRAMU
\*----------------------------------------------------------------------------*/
// Spolecne casti callbacku
//
#define Cbinitjob_memory(p) ((p)->memoryv.memp = malloc((p)->memoryv.size))
#define Cbinitjob_unknown(p) \
Report(REPORT_PROMPT_INIT "Unknown line: \"%s\"\n", (p)->linep)
/*
rpn32initarg_t *p;
*/
// Cislo radku vstupniho souboru resp. argumentu na "command-line"
//
#define LINENO_START 1
#define Lineno_error(n) Report(REPORT_PROMPT_INIT "Line #%u\n", (n))
/*............................................................................*\
Z COMMAND-LINE
\*............................................................................*/
// Test: je to ?
//
#define _ARG_2CHARS(a, b) ((a) | (b) << CHAR_BIT)
#define _ARG_2CHARS_SEPARATOR '=' // oddelovac argumentu
#define _ARG_2CHARS_XMULTI 'x' // alternativni znak nasobeni
#define _ARG_2CHARS_STDIN OPTCHAR_1ST // nahradni jmeno pro "stdin"
//
#define ARG_2CHARS_IS(k, t) (_ARG_2CHARS((t)[0], (t)[1]) == \
_ARG_2CHARS(_ARG_2CHARS_##k, '\0'))
/*
* CALLBACK
*/
struct fromargs
{
unsigned lineno;
int argc;
char **argv;
};
static int cb_init_job_fromarg(int type,
rpn32initarg_t *iap,
void *userdata)
{
#define fromp ((struct fromargs *)userdata)
switch(type)
{
case RPN32_INIT_CB_TYPE_MEMORY:
Cbinitjob_memory(iap);
return(RPN32_RTNVAL_DONE);
case RPN32_INIT_CB_TYPE_UNKNOWN:
Cbinitjob_unknown(iap);
return(RPN32_RTNVAL_DONE);
}
if(fromp->argc > 0)
if(!ARG_2CHARS_IS(SEPARATOR, *fromp->argv))
{
iap->linep = ARG_2CHARS_IS(XMULTI, *fromp->argv) ?
RPN32_TEXT_CODE_STR_MUL
:
*fromp->argv;
--fromp->argc;
++fromp->argv;
++fromp->lineno;
return(RPN32_RTNVAL_DONE);
}
return(RPN32_RTNVAL_STOP);
#undef fromp
}
/*
* VSTUPNI BOD
*/
static int init_job_fromarg(int *argcp,
char *argv[])
{
int test;
struct fromargs fromv;
fromv.argc = *argcp;
fromv.argv = argv;
fromv.lineno = LINENO_START - 1;
test = rpn32_init(&hndp, cb_init_job_fromarg, &fromv);
*argcp -= fromv.argc;
if(RPN32_RTNVAL_IS_ERROR(test))
Lineno_error(fromv.lineno);
return(test);
}
/*............................................................................*\
ZE SOUBORU
\*............................................................................*/
// Vycteni radky textu ze souboru
//
#define Line_get(l, f) (fgets(l, sizeof(l) - 1, f) != NULL)
#define Line_term(l) ((l)[strlen(l) - 1] = '\0')
// Velikost (pocet znaku) jedne radky
//
#define LINE_SIZE 80
/*
* CALLBACK
*/
struct fromfiles
{
FILE *fp;
char *commentp;
unsigned lineno;
char linet[LINE_SIZE];
};
static int cb_init_job_fromfile(int type,
rpn32initarg_t *iap,
void *userdata)
{
#define fromp ((struct fromfiles *)userdata)
switch(type)
{
case RPN32_INIT_CB_TYPE_MEMORY:
Cbinitjob_memory(iap);
return(RPN32_RTNVAL_DONE);
case RPN32_INIT_CB_TYPE_UNKNOWN:
if(fromp->commentp != NULL)
{
*fromp->commentp = *optcommentp;
fromp->commentp = NULL;
}
Cbinitjob_unknown(iap);
return(RPN32_RTNVAL_DONE);
}
while(Line_get(fromp->linet, fromp->fp))
{
Line_term(fromp->linet);
iap->linep = fromp->linet;
++fromp->lineno;
if(( fromp->commentp = strstr(iap->linep, optcommentp)) != NULL)
*fromp->commentp = '\0';
if(*iap->linep == '\0')
continue;
return(RPN32_RTNVAL_DONE);
}
return(RPN32_RTNVAL_STOP);
#undef fromp
}
/*
* VSTUPNI BOD
*/
static int init_job_fromfile(FILE *fp)
{
int test;
struct fromfiles fromv;
fromv.fp = fp;
fromv.commentp = NULL;
fromv.lineno = LINENO_START;
test = rpn32_init(&hndp, cb_init_job_fromfile, &fromv);
if(RPN32_RTNVAL_IS_ERROR(test))
Lineno_error(fromv.lineno);
return(test);
}
/*............................................................................*\
Z OBOU MOZNYCH ZDROJU
\*............................................................................*/
/*
* VSTUPNI BOD
*/
static int init_job(int argc,
char *argv[])
{
int test,
inca;
FILE *fp;
if(argc <= 0)
return(init_job_fromfile(stdin));
do
{
switch(0)
{
default:
if(ARG_2CHARS_IS(STDIN, *argv))
{
fp = stdin;
break;
}
if((fp = fopen(*argv, "r")) != NULL)
break;
inca = argc;
test = init_job_fromarg(&inca, argv);
continue;
}
test = init_job_fromfile(fp);
fclose(fp);
inca = 1;
} while(0);
if(RPN32_RTNVAL_IS_ERROR(test))
return(test);
argc -= inca;
argv += inca;
inca = RPN32_RTNVAL_DONE;
while(argc > 0)
{
if(ARG_2CHARS_IS(SEPARATOR, *argv))
inca = RPN32_RTNVAL_STOP;
else
if(RPN32_RTNVAL_IS_ERROR(test = rpn32_tenter(hndp, *argv)))
{
Report(REPORT_PROMPT_INIT "Bad value (value): \"%s\"\n", *argv);
return(test);
}
else
inca = RPN32_RTNVAL_DONE;
--argc;
++argv;
}
return(inca);
}
/*============================================================================*\
PROVADENI RPN PROGRAMU
\*============================================================================*/
// Prompty
//
#define VIEW_PROMPT_ERROR REPORT_PROMPT(ERR)
#define VIEW_PROMPT_TRACE REPORT_PROMPT(TRC)
#define VIEW_PROMPT_PSE REPORT_PROMPT(PSE)
#define VIEW_PROMPT_RESULT REPORT_PROMPT(RES)
#define VIEW_PROMPT_NONE REPORT_PROMPT(>>>)
#define VIEW_PROMPT_MODE REPORT_PROMPT(MOD)
//
#define ERRC_PROMPT_RUN REPORT_PROMPT(RUN)
#define ERRC_PROMPT_LIST REPORT_PROMPT(LST)
#define ERRC_PROMPT_SST REPORT_PROMPT(SST)
#define ERRC_PROMPT_GTO REPORT_PROMPT(GTO)
#define ERRC_PROMPT_INIT REPORT_PROMPT_INIT
// Chybova hlaseni
//
#define Errorcode(t, c) Report(ERRC_PROMPT_##t "%d: %s\n", \
(c), \
rtnval_text(c))
#define Errorline(m) rpn32_view(hndp, \
DFLT_VIEW_MODE_##m, \
cb_rpn32_view, \
VIEW_PROMPT_ERROR)
/*
* VYPIS PROGRAMU
*/
static int listing(char const *modep)
{
int test;
if(modep[0] == '\0')
modep = optmodelstp;
test = rpn32_list(hndp, modep, cb_rpn32_listmem, NULL);
if(!RPN32_RTNVAL_IS_ERROR(test))
return(0);
Errorcode(LIST, test);
Errorline(LIST);
return(-1);
}
/*
* VYPISY: "TRACE" NEBO "PSE"
*/
static int cb_rpn32_run(int type,
void *userdata)
{
return(rpn32_view(hndp,
userdata,
cb_rpn32_view,
type == RPN32_RUN_CB_TYPE_TRACE ?
VIEW_PROMPT_TRACE
:
VIEW_PROMPT_PSE));
}
/*
* VSTUPNI BOD
*/
static int execute(int type,
char const *modetrcp,
char const *moderesp)
{
#define test type
test = rpn32_run(hndp, type, cb_rpn32_run, (void *)modetrcp);
if(RPN32_RTNVAL_IS_ERROR(test))
{
Errorcode(RUN, test);
Errorline(TRACE);
return(-1);
}
rpn32_view(hndp, moderesp, cb_rpn32_view, VIEW_PROMPT_RESULT);
return(0);
#undef test
}
/*============================================================================*\
INTERAKTIVNI MOD
\*============================================================================*/
// "MODE" pro vypis/zobrazeni
//
static char interactivemodet[LINE_SIZE] =
DFLT_VIEW_MODE_TRACE;
/*
* URCENI "MODE"
*/
#define INTERACTIVE_MODE_LINE0_DFLT '\0'
#define INTERACTIVE_MODE_LINE0_NONE '-' // bez vypisu
#define INTERACTIVE_MODE_LINE0_OPT '+' // podle "optmodetrcp"
static char const *interactive_mode(char const *linep)
{
switch(linep[0])
{
case INTERACTIVE_MODE_LINE0_DFLT:
linep = interactivemodet;
break;
case INTERACTIVE_MODE_LINE0_NONE:
linep = NULL;
break;
case INTERACTIVE_MODE_LINE0_OPT:
linep = optmodetrcp;
}
return(linep);
}
// Navratove hodnoty
//
#define INTERACTIVE_RTNVAL_BYE (RPN32_RTNVAL_USER + 1)
#define INTERACTIVE_RTNVAL_NONE (RPN32_RTNVAL_USER + 0)
#define INTERACTIVE_RTNVAL_CMD RPN32_RTNVAL_STOP
#define INTERACTIVE_RTNVAL_SST RPN32_RTNVAL_DONE
/*
* COMMAND NELZE VYKONAT
*/
static int interactive_sorry(char const *texp)
{
printf("Sorry... (%s)\n", texp);
return(INTERACTIVE_RTNVAL_NONE);
}
static int interactive_sorry_arg()
{
return(interactive_sorry("Argument not expected"));
}
// Vypis/zobrazeni
//
#define interactive_spy(m) \
rpn32_view(hndp, interactive_mode(m), cb_rpn32_view, VIEW_PROMPT_NONE)
#define interactive_spy_dflt() \
interactive_spy(interactivemodet)
/*----------------------------------------------------------------------------*\
JEDNOTLIVE COMMANDY
\*----------------------------------------------------------------------------*/
// Textovy tvar prikazu
//
#define INTERACTIVE_CMD_TEXT_LIST "lst"
#define INTERACTIVE_CMD_TEXT_MEMUSAGE "mem"
#define INTERACTIVE_CMD_TEXT_SPY "spy"
#define INTERACTIVE_CMD_TEXT_SST "sst"
#define INTERACTIVE_CMD_TEXT_RUN "run"
#define INTERACTIVE_CMD_TEXT_COMMAND "cmd"
#define INTERACTIVE_CMD_TEXT_MODE "mod"
#define INTERACTIVE_CMD_TEXT_HELP "hlp"
#define INTERACTIVE_CMD_TEXT_BYE "bye"
//
#define INTERACTIVE_CMD_LEN 3
// Spolecne promenne
//
struct inters
{
char const *prompt_;
int (*fncp)(struct inters *);
char const *linep,
*sstmodep;
char linet[LINE_SIZE];
};
//
static char const interSSTprompt_[] = REPORT_PROMPT(SST),
interCMDprompt_[] = REPORT_PROMPT(CMD);
//
#define INTERS_IS(k, p) ((p)->prompt_ == inter##k##prompt_)
#define INTERS_SET(k, p) ((p)->prompt_ = inter##k##prompt_)
#define INTERS_PROMPT(p) ((p)->prompt_)
/*
* VYPIS
*/
static int interactive_cmd_LIST(struct inters *interp)
{
listing(interp->linep);
return(INTERACTIVE_RTNVAL_NONE);
}
/*
* VYPIS ROZSAHU CISEL PAMETOVYCH REGISTRU A NAVESTI
*/
#define Memusage() rpn32_mem(hndp, cb_rpn32_listmem, NULL)
static int interactive_cmd_MEMUSAGE(struct inters *interp)
{
if(interp->linep[0] != '\0')
return(interactive_sorry_arg());
Memusage();
return(INTERACTIVE_RTNVAL_NONE);
}
/*
* AKTUALNI HODNOTY
*/
static int interactive_cmd_SPY(struct inters *interp)
{
interactive_spy(interp->linep);
return(INTERACTIVE_RTNVAL_NONE);
}
/*
* SINGLE STEP
*/
static int interactive_one(struct inters *);
static int cb_rpn32_sst(int type,
void *userdata)
{
#define interp ((struct inters *)userdata)
type = type;
INTERS_SET(SST, interp);
rpn32_view(hndp, interp->sstmodep, cb_rpn32_view, VIEW_PROMPT_NONE);
return(interactive_one(interp));
#undef interp
}
static int interactive_sst_run(struct inters *interp)
{
int test;
test = rpn32_run(hndp, RPN32_RUN_CB_TYPE_TRACE, cb_rpn32_sst, interp);
if(!RPN32_RTNVAL_IS_ERROR(test))
return(test);
Errorcode(SST, test);
Errorline(TRACE);
return(INTERACTIVE_RTNVAL_CMD);
}
static int interactive_sst_run_mode(struct inters *interp)
{
char modet[LINE_SIZE - INTERACTIVE_CMD_LEN];
strcpy(modet, interp->sstmodep);
interp->sstmodep = modet;
return(interactive_sst_run(interp));
}
static int interactive_sst(struct inters *interp)
{
if((interp->sstmodep = interactive_mode(interp->linep)) != NULL)
return(interactive_sst_run_mode(interp));
interp->sstmodep = interactivemodet;
return(interactive_sst_run(interp));
}
static int interactive_cmd_SST(struct inters *interp)
{
if(INTERS_IS(CMD, interp))
return(interactive_sst(interp));
interp->fncp = interactive_sst;
return(INTERACTIVE_RTNVAL_CMD);
}
/*
* KONEC REZIMU SIGNLE STEP
*/
static int interactive_cmd_COMMAND(struct inters *interp)
{
if(interp->linep[0] != '\0')
return(interactive_sorry_arg());
return(INTERACTIVE_RTNVAL_CMD);
}
/*
* SPUSTENI/POKRACOVANI PROGRAMU
*/
static int interactive_run(struct inters *interp)
{
int runcbtype;
char const *modep;
runcbtype = RPN32_RUN_CB_TYPE_TRACE;
if((modep = interactive_mode(interp->linep)) == NULL)
{
modep = interactivemodet;
runcbtype = RPN32_RUN_CB_TYPE_PSE;
}
execute(runcbtype, modep, modep);
return(INTERACTIVE_RTNVAL_CMD);
}
static int interactive_cmd_RUN(struct inters *interp)
{
interp->fncp = interactive_run;
return(INTERACTIVE_RTNVAL_CMD);
}
/*
* NASTAVENI "MODE" PRO VYPIS/ZOBRAZENI
*/
static int interactive_cmd_MODE(struct inters *interp)
{
char const *linep;
linep = interp->linep;
if(linep[0] != '\0')
strcpy(interactivemodet, linep); // urcite se vejde, viz "LINE_SIZE"
else
Report(VIEW_PROMPT_MODE "%s\n", interactivemodet);
return(INTERACTIVE_RTNVAL_NONE);
}
/*
* NAPOVEDA
*/
static int interactive_cmd_HELP(struct inters *interp)
{
if(interp->linep[0] != '\0')
return(interactive_sorry_arg());
Outline(HELP_TEXT_INTERACTIVE);
Outline(HELP_TEXT_MODE_FORMAT);
return(INTERACTIVE_RTNVAL_NONE);
}
/*
* KONEC PROGRAMU
*/
static int interactive_cmd_BYE(struct inters *interp)
{
if(interp->linep[0] != '\0')
return(interactive_sorry_arg());
return(INTERACTIVE_RTNVAL_BYE);
}
/*
* ZPRACOVANI PROGRAMOVE RADKY
*/
static int interactive_now(struct inters *interp)
{
int test;
if(RPN32_RTNVAL_IS_ERROR(test = rpn32_now(hndp, interp->linep)))
return(interactive_sorry(rtnval_text(test)));
switch(test)
{
case RPN32_NOW_RTNVAL_YES:
printf("YES\n");
break;
case RPN32_NOW_RTNVAL_NO:
printf("NO\n");
break;
default:
interactive_spy_dflt();
}
return(INTERACTIVE_RTNVAL_NONE);
}
/*----------------------------------------------------------------------------*\
ZPRACOVANI VSTUPU Z KLAVESNICE
\*----------------------------------------------------------------------------*/
/*
* POROVNANI RETEZCU
*/
static int interactive_one_cmd_compare(char const *linep,
char const *namep)
{
while(tolower(*linep) == *namep)
{
++linep;
++namep;
if(*namep == '\0')
return(0);
}
return(-1);
}
/*
* ROZLISENI COMMANDU
*/
static int (*interactive_one_cmd(char const *linep))(struct inters *)
{
#define SORTIMENT_ITEM(k) {INTERACTIVE_CMD_TEXT_##k, interactive_cmd_##k}
int idx;
static struct
{
char namet[INTERACTIVE_CMD_LEN + 1];
int (*fncp)(struct inters *);
} const sortiment[] = {SORTIMENT_ITEM(LIST),
SORTIMENT_ITEM(MEMUSAGE),
SORTIMENT_ITEM(SPY),
SORTIMENT_ITEM(SST),
SORTIMENT_ITEM(COMMAND),
SORTIMENT_ITEM(RUN),
SORTIMENT_ITEM(MODE),
SORTIMENT_ITEM(HELP),
SORTIMENT_ITEM(BYE)};
for(idx = 0; idx < sizeof(sortiment) / sizeof(*sortiment); ++idx)
if(!interactive_one_cmd_compare(linep, sortiment[idx].namet))
return(sortiment[idx].fncp);
return(NULL);
#undef SORTIMENT_ITEM
}
/*
* PRESKOCENI "NEPLATNYCH" ZNAKU
*/
static char const *interactive_one_skip(char const *linep)
{
while(isspace(*linep))
++linep;
return(linep);
}
/*
* JEDNA "OTACKA"
*/
static int interactive_one(struct inters *interp)
{
int (*fncp)(struct inters *);
while(1)
{
printf(INTERS_PROMPT(interp));
if(!Line_get(interp->linet, stdin))
{
putchar('\n');
return(INTERACTIVE_RTNVAL_BYE);
}
Line_term(interp->linet);
interp->linep = interactive_one_skip(interp->linet);
if(interp->linep[0] == '\0')
{
if(INTERS_IS(SST, interp))
return(INTERACTIVE_RTNVAL_SST);
interactive_spy_dflt();
continue;
}
if((fncp = interactive_one_cmd(interp->linep)) != NULL)
{
int test;
interp->linep = interactive_one_skip(
interp->linep + INTERACTIVE_CMD_LEN);
if((test = (*fncp)(interp)) == INTERACTIVE_RTNVAL_NONE)
continue;
return(test);
}
interp->fncp = interactive_now;
return(INTERACTIVE_RTNVAL_CMD);
}
}
/*
* VSTUPNI BOD
*/
static void interactive()
{
struct inters interv;
reportprefixp = NULL;
interv.fncp = NULL;
interv.linep = NULL;
while(1)
{
INTERS_SET(CMD, &interv);
if(interactive_one(&interv) == INTERACTIVE_RTNVAL_BYE)
break;
if(interv.fncp == NULL)
continue;
(*interv.fncp)(&interv);
interv.fncp = NULL;
}
}
/*============================================================================*\
PROGRAM
\*============================================================================*/
/*
* INICIALIZACE
*/
static int initialize(int argc,
char *argv[])
{
int test;
struct initopts initoptv;
initoptv.flags = INITOPT_FLAGS_EXEC;
initoptv.startlbl = -1;
initoptv.runcbtype = RPN32_RUN_CB_TYPE_PSE;
if((test = init_options(argc, argv, &initoptv)) < 0)
return(test);
argv += argc - test;
argc = test;
if(RPN32_RTNVAL_IS_ERROR(test = init_job(argc, argv)))
{
Errorcode(INIT, test);
if(hndp != NULL)
Errorline(LIST);
return(-1);
}
if(test == RPN32_RTNVAL_STOP)
return(1);
if(initoptv.flags & INITOPT_FLAGS_LIST)
if(listing(optmodelstp))
return(-1);
if(initoptv.flags & INITOPT_FLAGS_MEMUSAGE)
Memusage();
if(!(initoptv.flags & INITOPT_FLAGS_EXEC))
return(0);
if(initoptv.startlbl >= 0)
if(RPN32_RTNVAL_IS_ERROR(test = rpn32_gto(hndp, initoptv.startlbl)))
{
Errorcode(GTO, test);
return(-1);
}
else
if(initoptv.runcbtype != RPN32_RUN_CB_TYPE_TRACE)
interactive_spy(optmodetrcp);
return(execute(initoptv.runcbtype, optmodetrcp, optmoderesp));
}
/*
* VSTUPNI BOD
*/
int main(int argc, char *argv[])
{
if((argc = initialize(argc, argv)) < 0)
return(1);
if(argc > 0)
interactive();
return(0);
}