mirror of
https://github.com/louisrubet/rpn
synced 2025-01-18 10:26:57 +01:00
creation
This commit is contained in:
commit
398f32c75e
16 changed files with 2104 additions and 0 deletions
BIN
HP-28S-Quick-Reference.pdf
Normal file
BIN
HP-28S-Quick-Reference.pdf
Normal file
Binary file not shown.
40
ReadMe.txt
Normal file
40
ReadMe.txt
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
========================================================================
|
||||||
|
CONSOLE APPLICATION : rpn Project Overview
|
||||||
|
========================================================================
|
||||||
|
|
||||||
|
AppWizard has created this rpn application for you.
|
||||||
|
|
||||||
|
This file contains a summary of what you will find in each of the files that
|
||||||
|
make up your rpn application.
|
||||||
|
|
||||||
|
|
||||||
|
rpn.vcxproj
|
||||||
|
This is the main project file for VC++ projects generated using an Application Wizard.
|
||||||
|
It contains information about the version of Visual C++ that generated the file, and
|
||||||
|
information about the platforms, configurations, and project features selected with the
|
||||||
|
Application Wizard.
|
||||||
|
|
||||||
|
rpn.vcxproj.filters
|
||||||
|
This is the filters file for VC++ projects generated using an Application Wizard.
|
||||||
|
It contains information about the association between the files in your project
|
||||||
|
and the filters. This association is used in the IDE to show grouping of files with
|
||||||
|
similar extensions under a specific node (for e.g. ".cpp" files are associated with the
|
||||||
|
"Source Files" filter).
|
||||||
|
|
||||||
|
rpn.cpp
|
||||||
|
This is the main application source file.
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
Other standard files:
|
||||||
|
|
||||||
|
StdAfx.h, StdAfx.cpp
|
||||||
|
These files are used to build a precompiled header (PCH) file
|
||||||
|
named rpn.pch and a precompiled types file named StdAfx.obj.
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
Other notes:
|
||||||
|
|
||||||
|
AppWizard uses "TODO:" comments to indicate parts of the source code you
|
||||||
|
should add to or customize.
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
82
TODO.txt
Normal file
82
TODO.txt
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* TODO en plus des commands hp28s
|
||||||
|
*/
|
||||||
|
general:
|
||||||
|
|
||||||
|
entry:
|
||||||
|
- parse en entier la ligne de commande puis si pas de pb de syntaxe entrer
|
||||||
|
- entrée sur plusieurs lignes
|
||||||
|
- entrée d'une variable sans '' = rcl
|
||||||
|
- rpn <"commande entière">
|
||||||
|
|
||||||
|
commands:
|
||||||
|
print
|
||||||
|
system
|
||||||
|
alias
|
||||||
|
alt-R + recherche ?
|
||||||
|
date / time
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FONCTIONNALITES en plus de celles marquées '*' dans la liste HP-28s commands
|
||||||
|
*/
|
||||||
|
verbose augmenter / diminuer la verbosité
|
||||||
|
vars lister les variables
|
||||||
|
erase effacer toute la stack
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HP-28s commands
|
||||||
|
*
|
||||||
|
* STACK
|
||||||
|
* DROP*, SWAP*, ROLL, DUP*, OVER, DUP2*, DROP2*, ROT*, LIST->, ROLLD, PICK, DUPN, DROPN, DEPTH*, ->LIST
|
||||||
|
*
|
||||||
|
* STORE
|
||||||
|
* STO*, RCL*, PURGE*, STO+, STO-, STO*, STO/, SNEG, SINV, SCONJ
|
||||||
|
*
|
||||||
|
* MEMORY
|
||||||
|
* MEM, MENU, ORDER, PATH, HOME, CRDIR, VARS, CLUSR
|
||||||
|
*
|
||||||
|
* ALGEBRA
|
||||||
|
* NEG*(+), COLCT, EXPAN, SIZE, FORM, OBSUB, EXSUB, TAYLR, ISOL, QUAD, SHOW, OBGET, EXGET
|
||||||
|
*
|
||||||
|
* STAT
|
||||||
|
* ∑DAT, ∑PAR, ∑+, ∑-, N∑, CL∑, STO∑, RCL∑, TOT, MEAN, SDEV, VAR, MAX∑, MIN∑, COL∑, CORR, COV, LR,
|
||||||
|
* PREDEV, UTPC, UTPF, UTPN, UTPT, COMB, PERM
|
||||||
|
*
|
||||||
|
* PRINT
|
||||||
|
* PR1, PRST, PRVAR, PRLCD, CR, TRAC, PRSTC, PRUSR, PRMD
|
||||||
|
*
|
||||||
|
* CONTRL
|
||||||
|
* SST, HALT, ABORT, KILL, WAIT, KEY, BEPP, CLLCD, DISP, CLMF, ERRN, ERRM
|
||||||
|
*
|
||||||
|
* BRANCH
|
||||||
|
* IF*, IFERR, THEN*, ELSE*, END*, START*, FOR*, NEXT*, STEP*, IFT, IFTE, DO, UNTIL, END, WHILE, REPEAT, END
|
||||||
|
*
|
||||||
|
* TEST
|
||||||
|
* !=*, >*, >=*, <*, <=*, SF, CF, FS?, FC?, FS?C, FC?C, AND, OR, XOR, NOT, SAME, ==*, STOF, RCLF, TYPE
|
||||||
|
*
|
||||||
|
* CATALOG
|
||||||
|
* NEXT, PREV, SCAN, USE, FETCH, QUIT
|
||||||
|
*
|
||||||
|
* UNITS
|
||||||
|
* CONVERT
|
||||||
|
*
|
||||||
|
* CURSOR
|
||||||
|
* INS, DEL, ← → ↑ ↓, STD, FIX, SCI, ENG, DEG, RAD, CMD, UNDO, LAST, ML, RDX, PRMD
|
||||||
|
*
|
||||||
|
* TRIG
|
||||||
|
* PI*(+), SIN*, ASIN*, COS*, ACOS*, TAN*, ATAN*, P→R, R→P, R→C, C→R, ARG, →HMS, HMS→, HMS+, HMS-, *D→R, *R→D
|
||||||
|
*
|
||||||
|
* LOGS
|
||||||
|
* LOG, ALOG, LN, EXP, LNP1, EXPM, SINH, ASINH, COSH, ACOSH, TANH, ATANH
|
||||||
|
*
|
||||||
|
* SOLV
|
||||||
|
* STEQ, RCEQ, ISOL, QUAD, SHOW, ROOT,
|
||||||
|
*
|
||||||
|
* PLOT
|
||||||
|
* PPAR, STEQ, RCEQ, PMIN, PMAX, INDEP, DRAW, RES, AXES, CENTR, *W, *H, STO∑, RCL∑, COL∑, SCL∑, DRW∑, CLLCD, DIGTIZ
|
||||||
|
*
|
||||||
|
* CUSTOM
|
||||||
|
* MENU, CUSTOM
|
||||||
|
*
|
||||||
|
* integration, differentiation, flags, reserved variables, system operations
|
||||||
|
*/
|
46
rpn-algebra.h
Normal file
46
rpn-algebra.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
void plus()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
ARG_IS_OF_TYPE(1, cmd_number);
|
||||||
|
|
||||||
|
putf(getf() + getf());
|
||||||
|
}
|
||||||
|
|
||||||
|
void minus()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
ARG_IS_OF_TYPE(1, cmd_number);
|
||||||
|
|
||||||
|
floating_t first = getf();
|
||||||
|
putf(getf() - first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mul()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
ARG_IS_OF_TYPE(1, cmd_number);
|
||||||
|
|
||||||
|
putf(getf() * getf());
|
||||||
|
}
|
||||||
|
|
||||||
|
void div()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
ARG_IS_OF_TYPE(1, cmd_number);
|
||||||
|
|
||||||
|
// arithmetic faults are managed by c++
|
||||||
|
floating_t first = getf();
|
||||||
|
putf(getf() / first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void neg()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
|
||||||
|
putf(-getf());
|
||||||
|
}
|
165
rpn-branch.h
Normal file
165
rpn-branch.h
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
//
|
||||||
|
int rpn_if(branch& myobj)
|
||||||
|
{
|
||||||
|
// myobj.arg1 = 'if' condition evaluation value
|
||||||
|
MIN_ARGUMENTS_RET(1, -1);
|
||||||
|
ARG_IS_OF_TYPE_RET(0, cmd_number, -1);
|
||||||
|
myobj.arg1 = ((getf() != 0) ? 1 : 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rpn_then(branch& myobj)
|
||||||
|
{
|
||||||
|
// myobj.arg1 = index of then + 1
|
||||||
|
// myobj.arg2 = index of else + 1 or end + 1
|
||||||
|
// myobj.arg3 = index of if
|
||||||
|
// if condition is true -> arg1 (= jump to then + 1)
|
||||||
|
// else -> arg2 (= jump to else + 1 or end + 1)
|
||||||
|
branch* if_cmd = (branch*)seq_obj(myobj.arg3);
|
||||||
|
if (if_cmd->arg1 == 1)
|
||||||
|
return myobj.arg1;
|
||||||
|
else
|
||||||
|
return myobj.arg2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rpn_else(branch& myobj)
|
||||||
|
{
|
||||||
|
// myobj.arg1 = index of else + 1
|
||||||
|
// myobj.arg2 = index of end + 1
|
||||||
|
// myobj.arg3 = index of if
|
||||||
|
// if condition was false -> arg1 (= jump to else + 1)
|
||||||
|
// if condition was true -> arg2 (= jump to end + 1)
|
||||||
|
branch* if_cmd = (branch*)seq_obj(myobj.arg3);
|
||||||
|
if (if_cmd->arg1 == 1)
|
||||||
|
return myobj.arg2;
|
||||||
|
else
|
||||||
|
return myobj.arg1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_end(void)
|
||||||
|
{
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
int rpn_start(branch& myobj)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS_RET(2, 1);
|
||||||
|
ARG_IS_OF_TYPE_RET(0, cmd_number, -1);
|
||||||
|
ARG_IS_OF_TYPE_RET(1, cmd_number, -1);
|
||||||
|
|
||||||
|
// farg1 = first value of start command
|
||||||
|
// farg2 = last value of start command
|
||||||
|
myobj.farg2 = getf();
|
||||||
|
myobj.farg1 = getf();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rpn_for(branch& myobj)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS_RET(2, 1);
|
||||||
|
ARG_IS_OF_TYPE_RET(0, cmd_number, -1);
|
||||||
|
ARG_IS_OF_TYPE_RET(1, cmd_number, -1);
|
||||||
|
|
||||||
|
symbol* sym = ((symbol*)seq_obj(myobj.arg1));
|
||||||
|
|
||||||
|
// farg1 = first value of for command
|
||||||
|
// farg2 = last value of for command
|
||||||
|
// arg1 = index of symbol to increase
|
||||||
|
myobj.farg2 = getf();
|
||||||
|
myobj.farg1 = getf();
|
||||||
|
|
||||||
|
// store symbol with first value
|
||||||
|
_heap->add(sym->_name, &number(myobj.farg1), sizeof(number), cmd_number);
|
||||||
|
|
||||||
|
return myobj.arg1 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rpn_next(branch& myobj)
|
||||||
|
{
|
||||||
|
// arg1 = index of start or for command in program
|
||||||
|
// farg1 = current count
|
||||||
|
branch* start_or_for = (branch*)seq_obj(myobj.arg1);
|
||||||
|
if (! myobj.arg_bool)
|
||||||
|
{
|
||||||
|
myobj.arg_bool = true;
|
||||||
|
myobj.farg1 = start_or_for->farg1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// increment then test
|
||||||
|
myobj.farg1++;
|
||||||
|
|
||||||
|
// for command: increment symbol too
|
||||||
|
if (start_or_for->arg1 != -1)
|
||||||
|
{
|
||||||
|
void* obj;
|
||||||
|
unsigned int size;
|
||||||
|
int type;
|
||||||
|
symbol* var = (symbol*)seq_obj(start_or_for->arg1);
|
||||||
|
// check symbol variable is a number, then increase
|
||||||
|
if (_heap->get(var->_name, obj, size, type) && (type == cmd_number))
|
||||||
|
((number*)obj)->_value = myobj.farg1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//test value
|
||||||
|
if (myobj.farg1 > start_or_for->farg2)
|
||||||
|
{
|
||||||
|
// end of loop
|
||||||
|
myobj.arg_bool = false;// init again next time
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// for command: next instruction will be after symbol variable
|
||||||
|
if (start_or_for->arg1 != -1)
|
||||||
|
return start_or_for->arg1 + 1;
|
||||||
|
// start command: next instruction will be after start command
|
||||||
|
else
|
||||||
|
return myobj.arg1 + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int rpn_step(branch& myobj)
|
||||||
|
{
|
||||||
|
// arg1 = index of start or for command in program
|
||||||
|
// farg1 = current count
|
||||||
|
floating_t step = getf();
|
||||||
|
branch* start_or_for = (branch*)seq_obj(myobj.arg1);
|
||||||
|
if (! myobj.arg_bool)
|
||||||
|
{
|
||||||
|
myobj.arg_bool = true;
|
||||||
|
myobj.farg1 = start_or_for->farg1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// increment then test
|
||||||
|
myobj.farg1 += step;
|
||||||
|
|
||||||
|
// for command: increment symbol too
|
||||||
|
if (start_or_for->arg1 != -1)
|
||||||
|
{
|
||||||
|
void* obj;
|
||||||
|
unsigned int size;
|
||||||
|
int type;
|
||||||
|
symbol* var = (symbol*)seq_obj(start_or_for->arg1);
|
||||||
|
// check symbol variable is a number, then increase
|
||||||
|
if (_heap->get(var->_name, obj, size, type) && (type == cmd_number))
|
||||||
|
((number*)obj)->_value = myobj.farg1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//test value
|
||||||
|
if (((step>0) && (myobj.farg1 > start_or_for->farg2))
|
||||||
|
|| ((step<0) && (myobj.farg1 < start_or_for->farg2)))
|
||||||
|
{
|
||||||
|
// end of loop
|
||||||
|
myobj.arg_bool = false;// init again next time
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// for command: next instruction will be after symbol variable
|
||||||
|
if (start_or_for->arg1 != -1)
|
||||||
|
return start_or_for->arg1 + 1;
|
||||||
|
// start command: next instruction will be after start command
|
||||||
|
else
|
||||||
|
return myobj.arg1 + 1;
|
||||||
|
}
|
||||||
|
}
|
89
rpn-cmd.h
Normal file
89
rpn-cmd.h
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
program::keyword_t program::_keywords[] =
|
||||||
|
{
|
||||||
|
//GENERAL
|
||||||
|
{ cmd_keyword, "", NULL, "\nGENERAL"},
|
||||||
|
{ cmd_keyword, "nop", &program::nop, "no operation"},
|
||||||
|
{ cmd_keyword, "?", &program::help, "" },
|
||||||
|
{ cmd_keyword, "h", &program::help, "" },
|
||||||
|
{ cmd_keyword, "help", &program::help, "(or h or ?) this help message" },
|
||||||
|
{ cmd_keyword, "q", &program::good_bye, "" },
|
||||||
|
{ cmd_keyword, "quit", &program::good_bye, "(or q or exit) quit software" },
|
||||||
|
{ cmd_keyword, "exit", &program::good_bye, "" },
|
||||||
|
{ cmd_keyword, "verbose", &program::verbose, "set verbosity, from 0 (not verbose) to > 0" },
|
||||||
|
{ cmd_keyword, "test", &program::test, "" }, //not seen by user
|
||||||
|
|
||||||
|
//ALGEBRA
|
||||||
|
{ cmd_undef, "", NULL, "\nALGEBRA"},
|
||||||
|
{ cmd_keyword, "+", &program::plus, "binary operator +" },
|
||||||
|
{ cmd_keyword, "-", &program::minus, "binary operator -" },
|
||||||
|
{ cmd_keyword, "neg", &program::neg , "unary operator - (negation)" },
|
||||||
|
{ cmd_keyword, "*", &program::mul, "binary operator *" },
|
||||||
|
{ cmd_keyword, "/", &program::div, "binary operator /" },
|
||||||
|
|
||||||
|
//TEST
|
||||||
|
{ cmd_undef, "", NULL, "\nTEST"},
|
||||||
|
{ cmd_keyword, ">", &program::sup, "binary operator >" },
|
||||||
|
{ cmd_keyword, ">=", &program::sup_eq, "binary operator >=" },
|
||||||
|
{ cmd_keyword, "<", &program::inf, "binary operator <" },
|
||||||
|
{ cmd_keyword, "<=", &program::inf_eq, "binary operator <=" },
|
||||||
|
{ cmd_keyword, "!=", &program::diff, "binary operator != (different)" },
|
||||||
|
{ cmd_keyword, "==", &program::eq , "binary operator == (equal)" },
|
||||||
|
|
||||||
|
//STACK
|
||||||
|
{ cmd_undef, "", NULL, "\nSTACK"},
|
||||||
|
{ cmd_keyword, "swap", &program::swap, "swap 2 first stack entries" },
|
||||||
|
{ cmd_keyword, "drop", &program::drop, "drop first stack entry" },
|
||||||
|
{ cmd_keyword, "drop2", &program::drop2, "drop 2 first stack entries" },
|
||||||
|
{ cmd_keyword, "erase", &program::erase, "drop all stack entries" },
|
||||||
|
{ cmd_keyword, "rot", &program::rot, "rotate 3 first stack entries" },
|
||||||
|
{ cmd_keyword, "dup", &program::dup, "duplicate first stack entry" },
|
||||||
|
{ cmd_keyword, "dup2", &program::dup2, "duplicate 2 first stack entries" },
|
||||||
|
{ cmd_keyword, "depth", &program::depth, "give stack depth" },
|
||||||
|
|
||||||
|
//BRANCH
|
||||||
|
{ cmd_undef, "", NULL, "\nBRANCH"},
|
||||||
|
{ cmd_branch, "if", (program_fn_t)&program::rpn_if, "<test-instructions>" },
|
||||||
|
{ cmd_branch, "then", (program_fn_t)&program::rpn_then, "<true-instructions>" },
|
||||||
|
{ cmd_branch, "else", (program_fn_t)&program::rpn_else, "<false-instructions>" },
|
||||||
|
{ cmd_keyword, "end", &program::rpn_end, "(end of if structure)" },
|
||||||
|
{ cmd_branch, "start", (program_fn_t)&program::rpn_start, "repeat instructions several times" },
|
||||||
|
{ cmd_branch, "for", (program_fn_t)&program::rpn_for, "repeat instructions several times with variable" },
|
||||||
|
{ cmd_branch, "next", (program_fn_t)&program::rpn_next, "ex: 1 10 start <instructions> next" },
|
||||||
|
{ cmd_branch, "step", (program_fn_t)&program::rpn_step, "ex: 1 100 start <instructions> 4 step" },
|
||||||
|
|
||||||
|
//STORE
|
||||||
|
{ cmd_undef, "", NULL, "\nSTORE"},
|
||||||
|
{ cmd_keyword, "sto", &program::sto, "store a variable. ex: 1 'name' sto" },
|
||||||
|
{ cmd_keyword, "rcl", &program::rcl, "recall a variable. ex: 'name' rcl" },
|
||||||
|
{ cmd_keyword, "purge", &program::purge, "delete a variable. ex: 'name' purge" },
|
||||||
|
{ cmd_keyword, "vars", &program::vars, "list all variables" },
|
||||||
|
|
||||||
|
//TRIG
|
||||||
|
{ cmd_undef, "", NULL, "\nTRIG"},
|
||||||
|
{ cmd_keyword, "pi", &program::pi, "PI constant" },
|
||||||
|
{ cmd_keyword, "sin", &program::rpn_sin, "sinus" },
|
||||||
|
{ cmd_keyword, "asin", &program::rpn_asin, "arg sinus" },
|
||||||
|
{ cmd_keyword, "cos", &program::rpn_cos , "cosinus" },
|
||||||
|
{ cmd_keyword, "acos", &program::rpn_acos, "arg cosinus" },
|
||||||
|
{ cmd_keyword, "tan", &program::rpn_tan, "tangent" },
|
||||||
|
{ cmd_keyword, "atan", &program::rpn_atan, "arg tangent" },
|
||||||
|
{ cmd_keyword, "d->r", &program::d2r, "convert degrees to radians" },
|
||||||
|
{ cmd_keyword, "r->d", &program::r2d, "convert radians to degrees" },
|
||||||
|
|
||||||
|
//LOGS
|
||||||
|
{ cmd_undef, "", NULL, "\nLOGS"},
|
||||||
|
{ cmd_keyword, "e", &program::rpn_e, "exp(0) constant" },
|
||||||
|
{ cmd_keyword, "log", &program::rpn_log, "logarithm base 10" },
|
||||||
|
{ cmd_keyword, "alog", &program::rpn_alog, "exponential base 10" },
|
||||||
|
{ cmd_keyword, "ln", &program::rpn_ln, "logarithm base e" },
|
||||||
|
{ cmd_keyword, "exp", &program::rpn_exp, "exponential" },
|
||||||
|
{ cmd_keyword, "sinh", &program::rpn_sinh, "hyperbolic sine" },
|
||||||
|
{ cmd_keyword, "asinh", &program::rpn_asinh, "inverse hyperbolic sine" },
|
||||||
|
{ cmd_keyword, "cosh", &program::rpn_sinh, "hyperbolic cosine" },
|
||||||
|
{ cmd_keyword, "acosh", &program::rpn_acosh, "inverse hyperbolic cosine" },
|
||||||
|
{ cmd_keyword, "tanh", &program::rpn_tanh, "hyperbolic tangent" },
|
||||||
|
{ cmd_keyword, "atanh", &program::rpn_atanh, "inverse hyperbolic tangent" },
|
||||||
|
|
||||||
|
// end
|
||||||
|
{ cmd_max, "", NULL, "" },
|
||||||
|
};
|
89
rpn-general-core.h
Normal file
89
rpn-general-core.h
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
void program::test()
|
||||||
|
{
|
||||||
|
const string test_filename = "test.txt";
|
||||||
|
ifstream test_file(test_filename);
|
||||||
|
if (test_file.is_open())
|
||||||
|
{
|
||||||
|
const string stack_size("-> stack size should be ");
|
||||||
|
const string stack_value("-> stack should be ");
|
||||||
|
string test_title;
|
||||||
|
string entry;
|
||||||
|
ret_value ret;
|
||||||
|
stack stk;
|
||||||
|
heap hp;
|
||||||
|
bool indicate_passed = false;
|
||||||
|
bool failed = false;
|
||||||
|
int count_tests = 0;
|
||||||
|
|
||||||
|
while (!test_file.eof())
|
||||||
|
{
|
||||||
|
getline(test_file, entry);
|
||||||
|
if (entry.substr(0,2)=="##")
|
||||||
|
{
|
||||||
|
if (indicate_passed)
|
||||||
|
cout << "passed " << count_tests << " tests"<< endl;
|
||||||
|
cout << entry << " .. ";
|
||||||
|
indicate_passed = true;
|
||||||
|
count_tests = 0;
|
||||||
|
}
|
||||||
|
else if (entry.substr(0,1)=="#")
|
||||||
|
{
|
||||||
|
test_title = entry;
|
||||||
|
count_tests++;
|
||||||
|
}
|
||||||
|
else if (entry.find(stack_size, 0) == 0)
|
||||||
|
{
|
||||||
|
istringstream isub;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
isub.str(entry.substr(stack_size.size()));
|
||||||
|
isub>>size;
|
||||||
|
if (stk.size() != size)
|
||||||
|
{
|
||||||
|
cout<<endl<<endl<<test_title<<endl<<entry<<endl<<"FAIL, ";
|
||||||
|
cout<<"real stack size is "<<stk.size()<<endl;
|
||||||
|
failed = true;
|
||||||
|
indicate_passed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (entry.find(stack_value, 0) == 0)
|
||||||
|
{
|
||||||
|
string stack_should_be = entry.substr(stack_value.size());
|
||||||
|
string stack_is;
|
||||||
|
string tmp;
|
||||||
|
for (int i = (int)stk.size() - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
stringstream os;
|
||||||
|
if (i < (int)(stk.size() - 1))
|
||||||
|
stack_is += ", ";
|
||||||
|
((object*)stk.seq_obj(i))->show(os);
|
||||||
|
getline(os, tmp);
|
||||||
|
stack_is += tmp;
|
||||||
|
}
|
||||||
|
if (stack_is != stack_should_be)
|
||||||
|
{
|
||||||
|
cout<<endl<<endl<<test_title<<endl<<entry<<endl<<"FAIL, ";
|
||||||
|
cout<<"real stack is "<<stack_is<<endl;
|
||||||
|
failed = true;
|
||||||
|
indicate_passed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (entry.size() > 0)
|
||||||
|
{
|
||||||
|
program prog;
|
||||||
|
ret = program::parse(entry, prog);
|
||||||
|
if (ret == ret_ok)
|
||||||
|
{
|
||||||
|
// run it
|
||||||
|
(void)prog.run(stk, hp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (indicate_passed)
|
||||||
|
cout << "passed " << count_tests << " tests"<< endl;
|
||||||
|
if (! failed)
|
||||||
|
cout << "test file '"<<test_filename<<"' has passed" << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cerr << "test file '"<<test_filename<<"' not found" << endl;
|
||||||
|
}
|
29
rpn-general.h
Normal file
29
rpn-general.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//
|
||||||
|
void nop()
|
||||||
|
{
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
|
void good_bye()
|
||||||
|
{
|
||||||
|
ERR_CONTEXT(ret_good_bye);
|
||||||
|
}
|
||||||
|
|
||||||
|
void verbose()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
g_verbose = (int)getf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void help()
|
||||||
|
{
|
||||||
|
for(int i=0; i<sizeof(_keywords)/sizeof(_keywords[0]); i++)
|
||||||
|
if (_keywords[i].comment.size() != 0)
|
||||||
|
cout<<_keywords[i].name<<"\t"<<_keywords[i].comment<<endl;
|
||||||
|
cout<<endl;
|
||||||
|
cout<<"Current verbosity is "<<g_verbose<<endl<<endl;
|
||||||
|
cout<<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test();
|
95
rpn-logs.h
Normal file
95
rpn-logs.h
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
void rpn_e(void)
|
||||||
|
{
|
||||||
|
putf(M_E);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_log()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value = log10(((number*)_stack->get_obj(0))->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_alog()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value = pow(((number*)_stack->get_obj(0))->_value, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_ln()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value = log(((number*)_stack->get_obj(0))->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_exp()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value = exp(((number*)_stack->get_obj(0))->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_sinh()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value = sinh(((number*)_stack->get_obj(0))->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_asinh()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
|
||||||
|
floating_t value = ((number*)_stack->get_obj(0))->_value;
|
||||||
|
if(value>0)
|
||||||
|
value = log(value + sqrt(value * value + 1));
|
||||||
|
else
|
||||||
|
value = -log(-value + sqrt(value * value + 1));
|
||||||
|
|
||||||
|
((number*)_stack->get_obj(0))->_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_cosh()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value = cosh(((number*)_stack->get_obj(0))->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_acosh()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
|
||||||
|
floating_t value = ((number*)_stack->get_obj(0))->_value;
|
||||||
|
if(value>0)
|
||||||
|
value = log(value + sqrt(value * value - 1));
|
||||||
|
else
|
||||||
|
value = -log(-value + sqrt(value * value - 1));
|
||||||
|
|
||||||
|
((number*)_stack->get_obj(0))->_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_tanh()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value = tanh(((number*)_stack->get_obj(0))->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_atanh()
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
|
||||||
|
floating_t value = ((number*)_stack->get_obj(0))->_value;
|
||||||
|
value = (log(1 + value) - log(1 - value)) / 2;
|
||||||
|
((number*)_stack->get_obj(0))->_value = value;
|
||||||
|
}
|
66
rpn-stack.h
Normal file
66
rpn-stack.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
//
|
||||||
|
void swap(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
_stack->copy_obj_to_local(0, 0);
|
||||||
|
_stack->copy_obj_to_local(1, 1);
|
||||||
|
_stack->pop_back();
|
||||||
|
_stack->pop_back();
|
||||||
|
_stack->push_obj_from_local(0);
|
||||||
|
_stack->push_obj_from_local(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drop(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
_stack->pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void drop2(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
_stack->pop_back();
|
||||||
|
_stack->pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase(void)
|
||||||
|
{
|
||||||
|
while(_stack->size()>0)
|
||||||
|
_stack->pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dup(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
_stack->copy_obj_to_local(0, 0);
|
||||||
|
_stack->push_obj_from_local(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dup2(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
_stack->copy_obj_to_local(0, 0);
|
||||||
|
_stack->copy_obj_to_local(1, 1);
|
||||||
|
_stack->push_obj_from_local(1);
|
||||||
|
_stack->push_obj_from_local(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rot(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(3);
|
||||||
|
_stack->copy_obj_to_local(0, 0);
|
||||||
|
_stack->copy_obj_to_local(1, 1);
|
||||||
|
_stack->copy_obj_to_local(2, 2);
|
||||||
|
_stack->pop_back();
|
||||||
|
_stack->pop_back();
|
||||||
|
_stack->pop_back();
|
||||||
|
_stack->push_obj_from_local(1);
|
||||||
|
_stack->push_obj_from_local(0);
|
||||||
|
_stack->push_obj_from_local(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void depth(void)
|
||||||
|
{
|
||||||
|
number num((floating_t)_stack->size());
|
||||||
|
_stack->push_back(&num, sizeof(number), cmd_number);
|
||||||
|
}
|
66
rpn-store.h
Normal file
66
rpn-store.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
//
|
||||||
|
void sto(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_symbol);
|
||||||
|
|
||||||
|
string name = getn();
|
||||||
|
_heap->add(name, _stack->get_obj(0), _stack->get_len(0), _stack->get_type(0));
|
||||||
|
_stack->pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rcl(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_symbol);
|
||||||
|
|
||||||
|
void* obj;
|
||||||
|
unsigned int size;
|
||||||
|
int type;
|
||||||
|
if (_heap->get(getn(), obj, size, type))
|
||||||
|
_stack->push_back(obj, size, type);
|
||||||
|
else
|
||||||
|
ERR_CONTEXT(ret_unknown_variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// carefull : this is not a langage command
|
||||||
|
void auto_rcl(symbol* symb)
|
||||||
|
{
|
||||||
|
if (symb->_auto_eval)
|
||||||
|
{
|
||||||
|
void* obj;
|
||||||
|
unsigned int size;
|
||||||
|
int type;
|
||||||
|
if (_heap->get(symb->_name, obj, size, type))
|
||||||
|
_stack->push_back(obj, size, type);
|
||||||
|
else
|
||||||
|
_stack->push_back(symb, sizeof(symbol), cmd_symbol);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_stack->push_back(symb, sizeof(symbol), cmd_symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
void purge(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_symbol);
|
||||||
|
|
||||||
|
if (!_heap->erase(getn()))
|
||||||
|
ERR_CONTEXT(ret_unknown_variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vars(void)
|
||||||
|
{
|
||||||
|
object* obj;
|
||||||
|
unsigned int size;
|
||||||
|
int type;
|
||||||
|
string name;
|
||||||
|
|
||||||
|
for (int i=0; i<(int)_heap->size(); i++)
|
||||||
|
{
|
||||||
|
(void)_heap->get_by_index(i, name, (void*&)obj, size, type);
|
||||||
|
cout<<"var "<<i+1<<": name '"<<name<<"', type "<<cmd_type_string[type]<<", value ";
|
||||||
|
obj->show();
|
||||||
|
cout<<endl;
|
||||||
|
}
|
||||||
|
}
|
85
rpn-test.h
Normal file
85
rpn-test.h
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
void sup(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
ARG_IS_OF_TYPE(1, cmd_number);
|
||||||
|
|
||||||
|
floating_t first = getf();
|
||||||
|
putf(getf() > first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sup_eq(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
ARG_IS_OF_TYPE(1, cmd_number);
|
||||||
|
|
||||||
|
floating_t first = getf();
|
||||||
|
putf(getf() >= first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void inf(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
ARG_IS_OF_TYPE(1, cmd_number);
|
||||||
|
|
||||||
|
floating_t first = getf();
|
||||||
|
putf(getf() < first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void inf_eq(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
ARG_IS_OF_TYPE(1, cmd_number);
|
||||||
|
|
||||||
|
floating_t first = getf();
|
||||||
|
putf(getf() <= first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void diff(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
ARG_IS_OF_TYPE(1, cmd_number);
|
||||||
|
|
||||||
|
floating_t first = getf();
|
||||||
|
putf(getf() != first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void eq(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(2);
|
||||||
|
int type = _stack->get_type(0);
|
||||||
|
|
||||||
|
if (_stack->get_type(1) == type)
|
||||||
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case cmd_number:
|
||||||
|
{
|
||||||
|
floating_t first = getf();
|
||||||
|
putf(getf() == first);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case cmd_symbol:
|
||||||
|
{
|
||||||
|
string first = getn();
|
||||||
|
putf(getn() == first);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_stack->pop_back();
|
||||||
|
_stack->pop_back();
|
||||||
|
putf(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_stack->pop_back();
|
||||||
|
_stack->pop_back();
|
||||||
|
putf(0);
|
||||||
|
}
|
||||||
|
}
|
64
rpn-trig.h
Normal file
64
rpn-trig.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
void pi(void)
|
||||||
|
{
|
||||||
|
putf(M_PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
void d2r(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value *= M_PI / 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
void r2d(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value *= 360 / M_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_sin(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value = sin(((number*)_stack->get_obj(0))->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_asin(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value = asin(((number*)_stack->get_obj(0))->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_cos(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value = cos(((number*)_stack->get_obj(0))->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_acos(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value = acos(((number*)_stack->get_obj(0))->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_tan(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value = tan(((number*)_stack->get_obj(0))->_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_atan(void)
|
||||||
|
{
|
||||||
|
MIN_ARGUMENTS(1);
|
||||||
|
ARG_IS_OF_TYPE(0, cmd_number);
|
||||||
|
((number*)_stack->get_obj(0))->_value = atan(((number*)_stack->get_obj(0))->_value);
|
||||||
|
}
|
694
rpn.cpp
Normal file
694
rpn.cpp
Normal file
|
@ -0,0 +1,694 @@
|
||||||
|
/*
|
||||||
|
* rpn.cpp
|
||||||
|
*
|
||||||
|
* Copyright 2013 <louis@rubet.fr>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <tchar.h>
|
||||||
|
#else
|
||||||
|
#define _TCHAR char
|
||||||
|
#define _tmain main
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#include "stack.h"
|
||||||
|
|
||||||
|
static const char CURSOR[] = "> ";
|
||||||
|
static const char SHOW_STACK_SEPARATOR[] = ":\t";
|
||||||
|
static int g_verbose = 0;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ret_ok,
|
||||||
|
ret_unknown_err,
|
||||||
|
ret_missing_operand,
|
||||||
|
ret_bad_operand_type,
|
||||||
|
ret_unknown_variable,
|
||||||
|
ret_internal,
|
||||||
|
ret_deadly,
|
||||||
|
ret_good_bye,
|
||||||
|
ret_not_impl,
|
||||||
|
ret_nop,
|
||||||
|
ret_syntax,
|
||||||
|
ret_max
|
||||||
|
} ret_value;
|
||||||
|
|
||||||
|
const char* ret_value_string[ret_max] = {
|
||||||
|
"ok", "unknown command", "missing operand", "bad operand type", "unknown variable", "internal error, aborting",
|
||||||
|
"deadly", "goodbye", "not implemented", "no operation", "syntax"
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
cmd_undef,
|
||||||
|
cmd_number,/* floating value to put in stack */
|
||||||
|
cmd_symbol,/* symbol value to put in stack */
|
||||||
|
cmd_keyword,/* langage keyword */
|
||||||
|
cmd_branch,/* langage branch keyword */
|
||||||
|
cmd_max
|
||||||
|
} cmd_type_t;
|
||||||
|
|
||||||
|
const char* cmd_type_string[cmd_max] = {
|
||||||
|
"undef", "number", "symbol", "keyword", "keyword"
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
typedef long double floating_t;
|
||||||
|
class program;
|
||||||
|
class object;
|
||||||
|
class branch;
|
||||||
|
typedef void (program::*program_fn_t)(void);
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
program_fn_t _fn;
|
||||||
|
} operand;
|
||||||
|
typedef int (program::*branch_fn_t)(branch&);
|
||||||
|
|
||||||
|
//
|
||||||
|
class object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cmd_type_t _type;// object type
|
||||||
|
object(cmd_type_t type = cmd_undef):_type(type) { }
|
||||||
|
virtual void show(ostream& stream = cout) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
class number : public object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
number(floating_t value) : object(cmd_number) { _value = value; }
|
||||||
|
virtual void show(ostream& stream = cout) { stream << _value; }
|
||||||
|
floating_t _value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class symbol : public object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
symbol(string& name, cmd_type_t type = cmd_symbol) : object(type), _name(name),_auto_eval(false) { }
|
||||||
|
virtual void show(ostream& stream = cout)
|
||||||
|
{
|
||||||
|
stream << "'" << _name << "'";
|
||||||
|
}
|
||||||
|
string _name;
|
||||||
|
bool _auto_eval;
|
||||||
|
};
|
||||||
|
|
||||||
|
class keyword : public symbol
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
keyword(program_fn_t fn, string& name, cmd_type_t type = cmd_keyword) : symbol(name, type) { _fn = fn; }
|
||||||
|
program_fn_t _fn;
|
||||||
|
virtual void show(ostream& stream = cout)
|
||||||
|
{
|
||||||
|
stream << _name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class branch : public keyword
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
branch(branch_fn_t fn, string& name) : keyword(NULL, name, cmd_branch), arg1(-1), arg2(-1), arg3(-1), arg_bool(false)
|
||||||
|
{
|
||||||
|
_type = cmd_branch;
|
||||||
|
_fn = fn;
|
||||||
|
}
|
||||||
|
// branch function
|
||||||
|
branch_fn_t _fn;
|
||||||
|
// args used by cmd_branch cmds
|
||||||
|
int arg1, arg2, arg3;
|
||||||
|
floating_t farg1, farg2, farg3;
|
||||||
|
bool arg_bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
class program : public stack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
program() { }
|
||||||
|
|
||||||
|
// run this program
|
||||||
|
ret_value run(stack& stk, heap& hp)
|
||||||
|
{
|
||||||
|
bool go_out = false;
|
||||||
|
ret_value ret = ret_ok;
|
||||||
|
cmd_type_t type;
|
||||||
|
|
||||||
|
_stack = &stk;
|
||||||
|
_heap = &hp;
|
||||||
|
_err = ret_ok;
|
||||||
|
_err_context = "";
|
||||||
|
|
||||||
|
// branches for 'if'
|
||||||
|
ret = preprocess();
|
||||||
|
if (ret != ret_ok)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
// iterate commands
|
||||||
|
for(int i = 0; (go_out==false) && (i<(int)size());)
|
||||||
|
{
|
||||||
|
type = (cmd_type_t)seq_type(i);
|
||||||
|
|
||||||
|
//
|
||||||
|
if (g_verbose >= 1)
|
||||||
|
{
|
||||||
|
cout << "(" << i << ") ";
|
||||||
|
((object*)seq_obj(i))->show();
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not a command, but a stack entry, manage it
|
||||||
|
if (type == cmd_number)
|
||||||
|
{
|
||||||
|
stk.push_back(seq_obj(i), seq_len(i), type);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// could be an auto-evaluated symbol
|
||||||
|
else if (type == cmd_symbol)
|
||||||
|
{
|
||||||
|
auto_rcl((symbol*)seq_obj(i));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// a keyword
|
||||||
|
else if (type == cmd_keyword)
|
||||||
|
{
|
||||||
|
keyword* k = (keyword*)seq_obj(i);
|
||||||
|
// call matching function
|
||||||
|
(this->*(k->_fn))();
|
||||||
|
switch(_err)
|
||||||
|
{
|
||||||
|
// no pb -> go on
|
||||||
|
case ret_ok:
|
||||||
|
break;
|
||||||
|
// explicit go out software
|
||||||
|
case ret_good_bye:
|
||||||
|
go_out = true;
|
||||||
|
ret = ret_good_bye;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error: abort prog
|
||||||
|
go_out = true;
|
||||||
|
|
||||||
|
// error: show it
|
||||||
|
if (show_error(_err, _err_context) == ret_deadly)
|
||||||
|
{
|
||||||
|
// pb showing error -> go out software
|
||||||
|
ret = ret_good_bye;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// a branch keyword
|
||||||
|
else if (type == cmd_branch)
|
||||||
|
{
|
||||||
|
// call matching function
|
||||||
|
branch* b = (branch*)seq_obj(i);
|
||||||
|
int tmp = (this->*(b->_fn))(*b);
|
||||||
|
if (tmp == -1)
|
||||||
|
i++;
|
||||||
|
else
|
||||||
|
i = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret_value preprocess(void)
|
||||||
|
{
|
||||||
|
struct if_layout_t
|
||||||
|
{
|
||||||
|
if_layout_t():index_then(-1),index_else(-1),index_end(-1) { }
|
||||||
|
int index_if;
|
||||||
|
int index_then;
|
||||||
|
int index_else;
|
||||||
|
int index_end;
|
||||||
|
};
|
||||||
|
|
||||||
|
// for if-then-else-end
|
||||||
|
vector<if_layout_t> vlayout;
|
||||||
|
int layout_index=-1;// TODO remplaçable par vlayout.size()-1
|
||||||
|
//for start-end-step
|
||||||
|
vector<int> vstartindex;
|
||||||
|
|
||||||
|
// analyse if-then-else-end branches
|
||||||
|
// analyse start-{next, step} branches
|
||||||
|
for(int i=0; i<(int)size(); i++)
|
||||||
|
{
|
||||||
|
int type = seq_type(i);
|
||||||
|
if (type == cmd_keyword)
|
||||||
|
{
|
||||||
|
keyword* k = (keyword*)seq_obj(i);
|
||||||
|
if(k->_name.compare("end") == 0)
|
||||||
|
{
|
||||||
|
int next = i + 1;
|
||||||
|
if (next >= (int)size())
|
||||||
|
next = -1;
|
||||||
|
|
||||||
|
if (layout_index<0)
|
||||||
|
{
|
||||||
|
// error: show it
|
||||||
|
show_syntax_error("missing if before end");
|
||||||
|
return ret_syntax;
|
||||||
|
}
|
||||||
|
if (vlayout[layout_index].index_end != -1)
|
||||||
|
{
|
||||||
|
// error: show it
|
||||||
|
show_syntax_error("duplicate end");
|
||||||
|
return ret_syntax;
|
||||||
|
}
|
||||||
|
((branch*)seq_obj(i))->arg1 = next;//fill branch1
|
||||||
|
if (vlayout[layout_index].index_else != -1)
|
||||||
|
//fill 'end' branch of 'else'
|
||||||
|
((branch*)seq_obj(vlayout[layout_index].index_else))->arg2 = i;
|
||||||
|
else
|
||||||
|
//fill 'end' branch of 'then'
|
||||||
|
((branch*)seq_obj(vlayout[layout_index].index_then))->arg2 = i;
|
||||||
|
layout_index--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == cmd_branch)
|
||||||
|
{
|
||||||
|
branch* k = (branch*)seq_obj(i);
|
||||||
|
if (k->_name.compare("if") == 0)
|
||||||
|
{
|
||||||
|
if_layout_t layout;
|
||||||
|
layout.index_if = i;
|
||||||
|
vlayout.push_back(layout);
|
||||||
|
layout_index++;
|
||||||
|
}
|
||||||
|
else if(k->_name.compare("then") == 0)
|
||||||
|
{
|
||||||
|
int next = i + 1;
|
||||||
|
if (next >= (int)size())
|
||||||
|
next = -1;
|
||||||
|
|
||||||
|
// nothing after 'then' -> error
|
||||||
|
if (next == -1)
|
||||||
|
{
|
||||||
|
// error: show it
|
||||||
|
show_syntax_error("missing end after then");
|
||||||
|
return ret_syntax;
|
||||||
|
}
|
||||||
|
if (layout_index<0)
|
||||||
|
{
|
||||||
|
// error: show it
|
||||||
|
show_syntax_error("missing if before then");
|
||||||
|
return ret_syntax;
|
||||||
|
}
|
||||||
|
if (vlayout[layout_index].index_then != -1)
|
||||||
|
{
|
||||||
|
// error: show it
|
||||||
|
show_syntax_error("duplicate then");
|
||||||
|
return ret_syntax;
|
||||||
|
}
|
||||||
|
vlayout[layout_index].index_then = i;
|
||||||
|
k->arg1 = next;
|
||||||
|
k->arg3 = vlayout[layout_index].index_if;
|
||||||
|
}
|
||||||
|
else if(k->_name.compare("else") == 0)
|
||||||
|
{
|
||||||
|
int next = i + 1;
|
||||||
|
if (next >= (int)size())
|
||||||
|
next = -1;
|
||||||
|
|
||||||
|
// nothing after 'else' -> error
|
||||||
|
if (next == -1)
|
||||||
|
{
|
||||||
|
// error: show it
|
||||||
|
show_syntax_error("missing end after else");
|
||||||
|
return ret_syntax;
|
||||||
|
}
|
||||||
|
if (layout_index<0)
|
||||||
|
{
|
||||||
|
// error: show it
|
||||||
|
show_syntax_error("missing if before else");
|
||||||
|
return ret_syntax;
|
||||||
|
}
|
||||||
|
if (vlayout[layout_index].index_then == -1)
|
||||||
|
{
|
||||||
|
// error: show it
|
||||||
|
show_syntax_error("missing then before else");
|
||||||
|
return ret_syntax;
|
||||||
|
}
|
||||||
|
if (vlayout[layout_index].index_else != -1)
|
||||||
|
{
|
||||||
|
// error: show it
|
||||||
|
show_syntax_error("duplicate else");
|
||||||
|
return ret_syntax;
|
||||||
|
}
|
||||||
|
vlayout[layout_index].index_else = i;
|
||||||
|
k->arg1 = next;// fill branch1 (if was false) of 'else'
|
||||||
|
k->arg3 = vlayout[layout_index].index_if;
|
||||||
|
((branch*)seq_obj(vlayout[layout_index].index_then))->arg2 = next;// fill branch2 (if was false) of 'then'
|
||||||
|
}
|
||||||
|
else if(k->_name.compare("start") == 0)
|
||||||
|
{
|
||||||
|
vstartindex.push_back(i);
|
||||||
|
}
|
||||||
|
else if(k->_name.compare("for") == 0)
|
||||||
|
{
|
||||||
|
vstartindex.push_back(i);
|
||||||
|
k->arg1 = i + 1;// arg1 points on symbol variable
|
||||||
|
}
|
||||||
|
else if(k->_name.compare("next") == 0)
|
||||||
|
{
|
||||||
|
if (vstartindex.size() == 0)
|
||||||
|
{
|
||||||
|
// error: show it
|
||||||
|
show_syntax_error("missing start or for before next");
|
||||||
|
return ret_syntax;
|
||||||
|
}
|
||||||
|
k->arg1 = vstartindex[vstartindex.size() - 1];// fill 'next' branch1 = 'start' index
|
||||||
|
vstartindex.pop_back();
|
||||||
|
}
|
||||||
|
else if(k->_name.compare("step") == 0)
|
||||||
|
{
|
||||||
|
if (vstartindex.size() == 0)
|
||||||
|
{
|
||||||
|
// error: show it
|
||||||
|
show_syntax_error("missing start or for before step");
|
||||||
|
return ret_syntax;
|
||||||
|
}
|
||||||
|
k->arg1 = vstartindex[vstartindex.size() - 1];// fill 'step' branch1 = 'start' index
|
||||||
|
vstartindex.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (layout_index >= 0)
|
||||||
|
{
|
||||||
|
// error: show it
|
||||||
|
show_syntax_error("missing end");
|
||||||
|
return ret_syntax;
|
||||||
|
}
|
||||||
|
if (vstartindex.size() > 0)
|
||||||
|
{
|
||||||
|
// error: show it
|
||||||
|
show_syntax_error("missing next or step after for or start");
|
||||||
|
return ret_syntax;
|
||||||
|
}
|
||||||
|
return ret_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ret_value show_error(ret_value err, string& context)
|
||||||
|
{
|
||||||
|
cerr<<context<<": "<<ret_value_string[err]<<endl;
|
||||||
|
switch(err)
|
||||||
|
{
|
||||||
|
case ret_internal:
|
||||||
|
case ret_deadly:
|
||||||
|
return ret_deadly;
|
||||||
|
default:
|
||||||
|
return ret_ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ret_value show_error(ret_value err, char* context)
|
||||||
|
{
|
||||||
|
string context_string(context);
|
||||||
|
return show_error(err, context_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_syntax_error(char* context)
|
||||||
|
{
|
||||||
|
cerr<<"syntax error: "<<context<<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// keywords declaration
|
||||||
|
struct keyword_t
|
||||||
|
{
|
||||||
|
cmd_type_t type;
|
||||||
|
string name;
|
||||||
|
program_fn_t fn;
|
||||||
|
string comment;
|
||||||
|
};
|
||||||
|
static keyword_t program::_keywords[100];
|
||||||
|
|
||||||
|
ret_value get_fn(const string& fn_name, program_fn_t& fn, cmd_type_t& type)
|
||||||
|
{
|
||||||
|
for(int i=0; (i<sizeof(_keywords)/sizeof(_keywords[0])) && (_keywords[i].type != cmd_max); i++)
|
||||||
|
{
|
||||||
|
if ((_keywords[i].name.size()>0) && (fn_name == _keywords[i].name))
|
||||||
|
{
|
||||||
|
fn = _keywords[i].fn;
|
||||||
|
type = _keywords[i].type;
|
||||||
|
return ret_ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret_unknown_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// interactive entry and decoding
|
||||||
|
static ret_value entry(program& prog)
|
||||||
|
{
|
||||||
|
ret_value ret;
|
||||||
|
string entry;
|
||||||
|
|
||||||
|
// show cursor
|
||||||
|
cout<<CURSOR;
|
||||||
|
|
||||||
|
// get user line
|
||||||
|
getline(cin, entry);
|
||||||
|
if (cin.good())
|
||||||
|
// parse it
|
||||||
|
ret = parse(entry, prog);
|
||||||
|
else
|
||||||
|
ret = ret_internal;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ret_value parse(const string& entry, program& prog)
|
||||||
|
{
|
||||||
|
ret_value ret = ret_ok;
|
||||||
|
istringstream stream(entry);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
floating_t num;
|
||||||
|
istringstream isub;
|
||||||
|
string sub;
|
||||||
|
|
||||||
|
stream >> sub;
|
||||||
|
isub.str(sub);
|
||||||
|
|
||||||
|
// check whether it is a number
|
||||||
|
isub >> num;
|
||||||
|
if ( (!isub.fail()) && (!isub.bad()) )
|
||||||
|
{
|
||||||
|
// found a number
|
||||||
|
prog.push_back(&number(num), sizeof(number), cmd_number);
|
||||||
|
if (isub.good())
|
||||||
|
{
|
||||||
|
// plus another command without space
|
||||||
|
program_fn_t fn;
|
||||||
|
cmd_type_t type;
|
||||||
|
isub >> sub;
|
||||||
|
if (prog.get_fn(sub, fn, type) != ret_ok)
|
||||||
|
program::show_error(ret_unknown_err, sub);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (type == cmd_keyword)
|
||||||
|
prog.push_back(&keyword(fn, sub), sizeof(keyword), cmd_keyword);
|
||||||
|
else if (type == cmd_branch)
|
||||||
|
prog.push_back(&branch((branch_fn_t)fn, sub), sizeof(branch), cmd_branch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (sub.size()>0)
|
||||||
|
{
|
||||||
|
// not a number ?
|
||||||
|
// could be a symbol
|
||||||
|
if (sub.substr(0,1) == "'")
|
||||||
|
{
|
||||||
|
// syntax should be 'symbol'
|
||||||
|
if (sub.substr(sub.size()-1, 1) == "'")
|
||||||
|
prog.push_back(&symbol(sub.substr(1, sub.size()-2)), sizeof(symbol), cmd_symbol);
|
||||||
|
// or 'symbol without ending ' only if last entry
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
stream.get(c);
|
||||||
|
if (stream.eof())
|
||||||
|
break;
|
||||||
|
sub += c;
|
||||||
|
}
|
||||||
|
while(c != '\'');
|
||||||
|
if (stream.eof())
|
||||||
|
prog.push_back(&symbol(sub.substr(1, sub.size()-1)), sizeof(symbol), cmd_symbol);
|
||||||
|
else
|
||||||
|
prog.push_back(&symbol(sub.substr(1, sub.size()-2)), sizeof(symbol), cmd_symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
program_fn_t fn;
|
||||||
|
cmd_type_t type;
|
||||||
|
// could be a command
|
||||||
|
if (prog.get_fn(sub, fn, type) == ret_ok)
|
||||||
|
{
|
||||||
|
if (type == cmd_keyword)
|
||||||
|
prog.push_back(&keyword(fn, sub), sizeof(keyword), cmd_keyword);
|
||||||
|
else if (type == cmd_branch)
|
||||||
|
prog.push_back(&branch((branch_fn_t)fn, sub), sizeof(branch), cmd_branch);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// no, so it is counted as an auto-evaluated symbol
|
||||||
|
symbol sym(sub);
|
||||||
|
sym._auto_eval = true;
|
||||||
|
prog.push_back(&sym, sizeof(symbol), cmd_symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!stream.eof());
|
||||||
|
|
||||||
|
// particular : check 'for' command is followed by a symbol, with auto-evaluated syntax (i.e. without ')
|
||||||
|
//TODO
|
||||||
|
/*
|
||||||
|
for(int i = 0; i < (int)prog.size(); i++)
|
||||||
|
{
|
||||||
|
if ((prog.seq_type(i) == cmd_branch) && ())
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_stack(stack& st)
|
||||||
|
{
|
||||||
|
if (st.size() == 1)
|
||||||
|
{
|
||||||
|
((object*)st.back())->show();
|
||||||
|
cout<<endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = st.size()-1; i>=0; i--)
|
||||||
|
{
|
||||||
|
cout<<i+1<<SHOW_STACK_SEPARATOR;
|
||||||
|
((object*)st[i])->show();
|
||||||
|
cout<<endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ret_value _err;
|
||||||
|
string _err_context;
|
||||||
|
stack* _stack;
|
||||||
|
heap* _heap;
|
||||||
|
|
||||||
|
// helpers for keywords implementation
|
||||||
|
floating_t getf()
|
||||||
|
{
|
||||||
|
/* warning, caller must check object type before */
|
||||||
|
floating_t a = ((number*)_stack->back())->_value;
|
||||||
|
_stack->pop_back();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void putf(floating_t value)
|
||||||
|
{
|
||||||
|
/* warning, caller must check object type before */
|
||||||
|
_stack->push_back(&number(value), sizeof(number), cmd_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
string getn()
|
||||||
|
{
|
||||||
|
/* warning, caller must check object type before */
|
||||||
|
string a = ((symbol*)_stack->back())->_name;
|
||||||
|
_stack->pop_back();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void putn(string& a)
|
||||||
|
{
|
||||||
|
/* warning, caller must check object type before */
|
||||||
|
_stack->push_back(&symbol(a), sizeof(symbol), cmd_symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
int stack_size()
|
||||||
|
{
|
||||||
|
return _stack->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// carefull : some of these macros modify program flow
|
||||||
|
#define ERR_CONTEXT(err) do { _err = (err); _err_context = __FUNCTION__; } while(0)
|
||||||
|
#define MIN_ARGUMENTS(num) do { if (stack_size()<(num)) { ERR_CONTEXT(ret_missing_operand); return; } } while(0)
|
||||||
|
#define MIN_ARGUMENTS_RET(num, ret) do { if (stack_size()<(num)) { ERR_CONTEXT(ret_missing_operand); return (ret); } } while(0)
|
||||||
|
#define ARG_IS_OF_TYPE(num, type) do { if (_stack->get_type(num) != (type)) { ERR_CONTEXT(ret_bad_operand_type); return; } } while(0)
|
||||||
|
#define ARG_IS_OF_TYPE_RET(num, type, ret) do { if (_stack->get_type(num) != (type)) { ERR_CONTEXT(ret_bad_operand_type); return (ret); } } while(0)
|
||||||
|
|
||||||
|
// keywords implementation
|
||||||
|
#include "rpn-general.h"
|
||||||
|
#include "rpn-algebra.h"
|
||||||
|
#include "rpn-test.h"
|
||||||
|
#include "rpn-stack.h"
|
||||||
|
#include "rpn-branch.h"
|
||||||
|
#include "rpn-store.h"
|
||||||
|
#include "rpn-trig.h"
|
||||||
|
#include "rpn-logs.h"
|
||||||
|
};
|
||||||
|
|
||||||
|
//keywords declaration
|
||||||
|
#include "rpn-cmd.h"
|
||||||
|
|
||||||
|
#include "rpn-general-core.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
int _tmain(int argc, _TCHAR* argv[])
|
||||||
|
{
|
||||||
|
heap hp;
|
||||||
|
stack st;
|
||||||
|
|
||||||
|
//
|
||||||
|
cout << setprecision(16);
|
||||||
|
|
||||||
|
//
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
program prog;
|
||||||
|
if (program::entry(prog) == ret_good_bye)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (prog.run(st, hp) == ret_good_bye)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
program::show_stack(st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
261
stack.h
Normal file
261
stack.h
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
#ifndef __stack_h__
|
||||||
|
#define __stack_h__
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define ALLOC_BLOB (128*1024)
|
||||||
|
#define LOCAL_COPY_PLACES 3
|
||||||
|
#define LOCAL_COPY_SIZE 128
|
||||||
|
|
||||||
|
//
|
||||||
|
class stack
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
struct local_copy
|
||||||
|
{
|
||||||
|
unsigned int length;
|
||||||
|
int type;
|
||||||
|
int blob;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
stack()
|
||||||
|
{
|
||||||
|
_base = (char*)malloc(ALLOC_BLOB);
|
||||||
|
_total_size = ALLOC_BLOB;
|
||||||
|
_current = _base;
|
||||||
|
_count = 0;
|
||||||
|
}
|
||||||
|
virtual ~stack() { free(_base); }
|
||||||
|
|
||||||
|
void push_back(void* obj, unsigned int size, int type = 0)
|
||||||
|
{
|
||||||
|
if (_current + size > _base + _total_size)
|
||||||
|
{
|
||||||
|
//TODO gérer les pbs de mémoire
|
||||||
|
_total_size += ALLOC_BLOB;
|
||||||
|
_base = (char*)realloc(_base, _total_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(_current, obj, size);
|
||||||
|
_vlen.push_back(size);
|
||||||
|
_vpointer.push_back(_current);
|
||||||
|
_vtype.push_back(type);
|
||||||
|
_count++;
|
||||||
|
_current += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_back()
|
||||||
|
{
|
||||||
|
if (_count > 0)
|
||||||
|
{
|
||||||
|
_current = _vpointer[_count - 1];
|
||||||
|
_vlen.pop_back();
|
||||||
|
_vpointer.pop_back();
|
||||||
|
_vtype.pop_back();
|
||||||
|
_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int size()
|
||||||
|
{
|
||||||
|
return _count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stack access (index is counted from back)
|
||||||
|
void* get_obj(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index<_count)
|
||||||
|
return _vpointer[_count-index-1];
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* operator[](unsigned int index)
|
||||||
|
{
|
||||||
|
return get_obj(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* back()
|
||||||
|
{
|
||||||
|
if (_count>0)
|
||||||
|
return _vpointer[_count-1];
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int get_len(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index<_count)
|
||||||
|
return _vlen[_count-index-1];
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_type(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index<_count)
|
||||||
|
return _vtype[_count-index-1];
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sequential access (index is counted from front)
|
||||||
|
void* seq_obj(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index<_count)
|
||||||
|
return _vpointer[index];
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int seq_len(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index<_count)
|
||||||
|
return _vlen[index];
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int seq_type(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index<_count)
|
||||||
|
return _vtype[index];
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// local objects copy
|
||||||
|
void copy_obj_to_local(unsigned int index, unsigned int to_place)
|
||||||
|
{
|
||||||
|
assert(to_place < LOCAL_COPY_PLACES);
|
||||||
|
struct local_copy* local = (struct local_copy*)_places[to_place];
|
||||||
|
local->length = get_len(index);
|
||||||
|
local->type= get_type(index);
|
||||||
|
memcpy(&local->blob, get_obj(index), local->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_obj_from_local(unsigned int from_place)
|
||||||
|
{
|
||||||
|
assert(from_place < LOCAL_COPY_PLACES);
|
||||||
|
struct local_copy* local = (struct local_copy*)_places[from_place];
|
||||||
|
push_back(&local->blob, local->length, local->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char* _base;
|
||||||
|
char* _current;
|
||||||
|
vector<unsigned int> _vlen;// size of each entry in bytes
|
||||||
|
vector<char*> _vpointer;//pointer on each entry
|
||||||
|
vector<int> _vtype;//type of each entry
|
||||||
|
unsigned int _count;// =_vlen.size()=_vpointer.size()=_vtype.size()
|
||||||
|
unsigned int _total_size;//total allocated size in bytes
|
||||||
|
|
||||||
|
char _places[LOCAL_COPY_PLACES][LOCAL_COPY_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
class heap
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
struct local_var
|
||||||
|
{
|
||||||
|
unsigned int length;
|
||||||
|
int type;
|
||||||
|
int blob;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
heap() { }
|
||||||
|
virtual ~heap()
|
||||||
|
{
|
||||||
|
for(map<string, struct local_var*>::iterator i=_map.begin(); i!=_map.end(); i++)
|
||||||
|
free(i->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(const string name, void* obj, unsigned int size, int type = 0)
|
||||||
|
{
|
||||||
|
struct local_var* blob = _map[name];
|
||||||
|
if (blob == NULL)
|
||||||
|
{
|
||||||
|
//TODO gérer les pbs de mémoire
|
||||||
|
blob = (struct local_var*)malloc(size + sizeof(local_var));
|
||||||
|
_map[name] = blob;
|
||||||
|
}
|
||||||
|
else if (size != blob->length)
|
||||||
|
{
|
||||||
|
//TODO gérer les pbs de mémoire
|
||||||
|
blob = (struct local_var*)realloc(blob, size + sizeof(local_var));
|
||||||
|
_map[name] = blob;
|
||||||
|
}
|
||||||
|
blob->length = size;
|
||||||
|
blob->type= type;
|
||||||
|
memcpy(&blob->blob, obj, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get(const string name, void*& obj, unsigned int& size, int& type)
|
||||||
|
{
|
||||||
|
map<string, struct local_var*>::iterator i = _map.find(name);
|
||||||
|
if (i != _map.end())
|
||||||
|
{
|
||||||
|
if (i->second != NULL)
|
||||||
|
{
|
||||||
|
obj = &i->second->blob;
|
||||||
|
size = i->second->length;
|
||||||
|
type = i->second->type;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool exist(const string name)
|
||||||
|
{
|
||||||
|
return (_map.find(name) != _map.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_by_index(int num, string& name, void*& obj, unsigned int& size, int& type)
|
||||||
|
{
|
||||||
|
if (num>=0 && num<(int)_map.size())
|
||||||
|
{
|
||||||
|
map<string, struct local_var*>::iterator i=_map.begin();
|
||||||
|
//TODO moche moche moche
|
||||||
|
for(int j=0;j<num;j++)
|
||||||
|
i++;
|
||||||
|
struct local_var* blob = (struct local_var*)i->second;
|
||||||
|
assert(blob != NULL);
|
||||||
|
|
||||||
|
name = i->first;
|
||||||
|
obj = &blob->blob;
|
||||||
|
size = blob->length;
|
||||||
|
type = blob->type;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool erase(const string name)
|
||||||
|
{
|
||||||
|
struct local_var* blob = _map[name];
|
||||||
|
if (blob != NULL)
|
||||||
|
{
|
||||||
|
free(blob);
|
||||||
|
_map.erase(_map.find(name));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int size() { return _map.size(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
map<string, struct local_var*> _map;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __stack_h__
|
233
test.txt
Normal file
233
test.txt
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
## 1 ## ENTRY and STACK
|
||||||
|
# test entry 1
|
||||||
|
1
|
||||||
|
-> stack size should be 1
|
||||||
|
|
||||||
|
# test entry 2
|
||||||
|
2 3
|
||||||
|
-> stack size should be 3
|
||||||
|
-> stack should be 3, 2, 1
|
||||||
|
|
||||||
|
# test drop
|
||||||
|
drop
|
||||||
|
-> stack size should be 2
|
||||||
|
|
||||||
|
# test drop2
|
||||||
|
drop2
|
||||||
|
-> stack size should be 0
|
||||||
|
|
||||||
|
# test symbol entry 1
|
||||||
|
1 '2'
|
||||||
|
-> stack size should be 2
|
||||||
|
-> stack should be '2', 1
|
||||||
|
drop2
|
||||||
|
|
||||||
|
# test symbol entry 2
|
||||||
|
1 '2
|
||||||
|
-> stack size should be 2
|
||||||
|
-> stack should be '2', 1
|
||||||
|
drop2
|
||||||
|
|
||||||
|
# test symbol entry 3
|
||||||
|
'2 3'
|
||||||
|
-> stack should be '2 3'
|
||||||
|
drop
|
||||||
|
|
||||||
|
# test symbol entry 4
|
||||||
|
'2 3
|
||||||
|
-> stack should be '2 3'
|
||||||
|
drop
|
||||||
|
|
||||||
|
# test symbol entry 5
|
||||||
|
''
|
||||||
|
-> stack should be ''
|
||||||
|
drop
|
||||||
|
|
||||||
|
# test symbol entry 6
|
||||||
|
'
|
||||||
|
-> stack should be ''
|
||||||
|
drop
|
||||||
|
|
||||||
|
# test dup
|
||||||
|
1 dup
|
||||||
|
-> stack size should be 2
|
||||||
|
-> stack should be 1, 1
|
||||||
|
|
||||||
|
# test dup2
|
||||||
|
drop 2 dup2
|
||||||
|
-> stack size should be 4
|
||||||
|
-> stack should be 2, 1, 2, 1
|
||||||
|
drop2 drop2
|
||||||
|
|
||||||
|
# test rot
|
||||||
|
1 2 3 rot
|
||||||
|
-> stack size should be 3
|
||||||
|
-> stack should be 1, 3, 2
|
||||||
|
|
||||||
|
# test depth
|
||||||
|
depth
|
||||||
|
-> stack size should be 4
|
||||||
|
-> stack should be 3, 1, 3, 2
|
||||||
|
drop2 drop2
|
||||||
|
|
||||||
|
## 2 ## BRANCH
|
||||||
|
# if-then-else-end test 1
|
||||||
|
1 if then 'ok' end
|
||||||
|
-> stack size should be 1
|
||||||
|
-> stack should be 'ok'
|
||||||
|
drop
|
||||||
|
|
||||||
|
# if-then-else-end test 2
|
||||||
|
0 if then 'ok' end
|
||||||
|
-> stack size should be 0
|
||||||
|
|
||||||
|
# if-then-else-end test 3
|
||||||
|
1 if 0 1 then 'ok' end
|
||||||
|
-> stack size should be 3
|
||||||
|
-> stack should be 'ok', 1, 0
|
||||||
|
drop2 drop
|
||||||
|
|
||||||
|
# if-then-else-end test 4
|
||||||
|
1 if then 'ok' else 0 end
|
||||||
|
-> stack size should be 1
|
||||||
|
-> stack should be 'ok'
|
||||||
|
drop
|
||||||
|
|
||||||
|
# if-then-else-end test 5
|
||||||
|
0 if then 'ok' else 0 end
|
||||||
|
-> stack size should be 1
|
||||||
|
-> stack should be 0
|
||||||
|
drop
|
||||||
|
|
||||||
|
# if-then-else-end test 6
|
||||||
|
1 if then 1 if then 'ok' else 0 end end
|
||||||
|
-> stack size should be 1
|
||||||
|
-> stack should be 'ok'
|
||||||
|
drop
|
||||||
|
|
||||||
|
# if-then-else-end test 7
|
||||||
|
1 if then 0 if then 'ok' else 0 end end
|
||||||
|
-> stack size should be 1
|
||||||
|
-> stack should be 0
|
||||||
|
drop
|
||||||
|
|
||||||
|
# if-then-else-end test 8
|
||||||
|
0 if then 0 if then 'ok' else 0 end else 'OK !' end
|
||||||
|
-> stack size should be 1
|
||||||
|
-> stack should be 'OK !'
|
||||||
|
drop
|
||||||
|
|
||||||
|
# start-next-step test 1
|
||||||
|
1 3 start 'ok' next
|
||||||
|
-> stack size should be 3
|
||||||
|
-> stack should be 'ok', 'ok', 'ok'
|
||||||
|
drop drop2
|
||||||
|
|
||||||
|
# start-next-step test 2
|
||||||
|
3 1 start 'ok' next
|
||||||
|
-> stack size should be 1
|
||||||
|
-> stack should be 'ok'
|
||||||
|
drop
|
||||||
|
|
||||||
|
# start-next-step test 3
|
||||||
|
-1 0 start 'ok' next
|
||||||
|
-> stack size should be 2
|
||||||
|
-> stack should be 'ok', 'ok'
|
||||||
|
drop2
|
||||||
|
|
||||||
|
# start-next-step test 4
|
||||||
|
0 4 start 'ok' 2 step
|
||||||
|
-> stack size should be 3
|
||||||
|
-> stack should be 'ok', 'ok', 'ok'
|
||||||
|
drop2 drop
|
||||||
|
|
||||||
|
# start-next-step test 5
|
||||||
|
0 -2 start 'ok' -1 step
|
||||||
|
-> stack size should be 3
|
||||||
|
-> stack should be 'ok', 'ok', 'ok'
|
||||||
|
drop2 drop
|
||||||
|
|
||||||
|
# start-next-step test 6
|
||||||
|
0 0.2 start 'ok' 0.1 step
|
||||||
|
-> stack size should be 3
|
||||||
|
-> stack should be 'ok', 'ok', 'ok'
|
||||||
|
drop2 drop
|
||||||
|
|
||||||
|
# for-next-step test 1
|
||||||
|
1 3 for i i next
|
||||||
|
-> stack size should be 3
|
||||||
|
-> stack should be 3, 2, 1
|
||||||
|
drop drop2
|
||||||
|
|
||||||
|
# for-next-step test 2
|
||||||
|
3 1 for i i next
|
||||||
|
-> stack size should be 1
|
||||||
|
-> stack should be 3
|
||||||
|
drop
|
||||||
|
|
||||||
|
# for-next-step test 3
|
||||||
|
-1 0 for i i next
|
||||||
|
-> stack size should be 2
|
||||||
|
-> stack should be 0, -1
|
||||||
|
drop2
|
||||||
|
|
||||||
|
# for-next-step test 4
|
||||||
|
0 4 for i i 2 step
|
||||||
|
-> stack size should be 3
|
||||||
|
-> stack should be 4, 2, 0
|
||||||
|
drop2 drop
|
||||||
|
|
||||||
|
# for-next-step test 5
|
||||||
|
0 -2 for i i -1 step
|
||||||
|
-> stack size should be 3
|
||||||
|
-> stack should be -2, -1, 0
|
||||||
|
drop2 drop
|
||||||
|
|
||||||
|
# for-next-step test 6
|
||||||
|
0 0.2 for i i 0.1 step
|
||||||
|
-> stack size should be 3
|
||||||
|
-> stack should be 0.2, 0.1, 0
|
||||||
|
drop2 drop
|
||||||
|
|
||||||
|
# for-next-step test 7
|
||||||
|
1 2 for i 10 20 for j i j + 10 step next
|
||||||
|
-> stack size should be 4
|
||||||
|
-> stack should be 22, 12, 21, 11
|
||||||
|
drop2 drop2
|
||||||
|
|
||||||
|
## 3 ## STORE
|
||||||
|
# sto test 1
|
||||||
|
1 'a' sto
|
||||||
|
-> stack size should be 0
|
||||||
|
|
||||||
|
# rcl test 1
|
||||||
|
'a' rcl
|
||||||
|
-> stack size should be 1
|
||||||
|
-> stack should be 1
|
||||||
|
drop
|
||||||
|
|
||||||
|
# sto test 2
|
||||||
|
'toto' 'b' sto
|
||||||
|
-> stack size should be 0
|
||||||
|
|
||||||
|
# rcl test 2
|
||||||
|
'b' rcl
|
||||||
|
-> stack size should be 1
|
||||||
|
-> stack should be 'toto'
|
||||||
|
drop
|
||||||
|
|
||||||
|
# sto/rcl test 1
|
||||||
|
'b' rcl 'a' sto 'a' rcl
|
||||||
|
-> stack size should be 1
|
||||||
|
-> stack should be 'toto'
|
||||||
|
drop
|
||||||
|
|
||||||
|
# purge test 1
|
||||||
|
'a' purge 'b' purge
|
||||||
|
-> stack size should be 0
|
||||||
|
|
||||||
|
# auto-eval test 1
|
||||||
|
1 'a' sto 1 3 start 1 a + 'a' sto next a
|
||||||
|
-> stack size should be 1
|
||||||
|
-> stack should be 4
|
||||||
|
drop
|
Loading…
Reference in a new issue