#include "main.h"
#include "benchmarking.h"
#include "editline.h"
#include "elemop.h"
#include "error.h"
#include "evalfn.h"
#include "exproriented.h"
#include "graphplot.h"
#include "mem.h"
#include "optexpr.h"
#include "rand.h"
#include "rc.h"
#include "testing.h"
auto eval_f = evalExprReal;
void (*print_complex)(comp) = printComplexComplex;
int main(int argc, char const **argv) {
initPlotCfg();
loadInitScript(nullptr);
procAList(argc - 1, argv + 1);
readerLoop(stdin);
return 0;
}
static void startupMsg() {
PRINT(
"===========================================================\n",
" RPX - Reverse Polish notation calculator eXtended\n",
"===========================================================\n",
" A powerful RPN calculator supporting multiple modes:\n",
" - Real numbers (default)\n",
" - comp numbers (:tc to toggle)\n",
"\n",
" Features:\n",
" - Register ($a to $z)\n",
" - Result history (@a, @h)\n",
" - Special constants (\\P for pi, \\E for e)\n",
" - Advanced functions (sin, cos, log, etc.)\n",
" - Matrix operations (in comp mode)\n",
"\n",
" Usage:\n",
" - Enter RPN expressions directly\n",
" - Use ':' for commands (e.g., :tc for comp mode)\n",
"\n",
" Examples:\n",
" 3 4 + 5 * -> 35\n",
" 2 \\P * s -> 0 (approximately)\n",
" [2; 2 2][2; 1 2 3 4]* -> [8,12] (matrix multiplication)\n",
"\n",
" Press Ctrl+D to exit the program.\n",
"===========================================================\n",
);
}
[[gnu::nonnull]] void procInput(char const *restrict input_buf) {
*input_buf == ':' ? procCmds(input_buf + 1) : printElem(eval_f(input_buf));
}
void procAList(int argc, char const **argv) {
if (argc == 0) return;
if (**argv != '-') { FILE *fp dropfile
= fopen(*argv, "r") ?: p$panic(ERR_FILE_NOT_FOUND, "%s ", *argv);
readerLoop(fp);
} else switch ((*argv)[1]) { case 'h':
startupMsg();
break;
case 'r':
procInput(*++argv);
break;
case 'q':
exit(0);
default:
panic(ERR_UNKNOWN_OPTION, "%c ", (*argv)[1]);
}
procAList(argc - 1, argv + 1);
}
static bool readRawLine(char *buf, size_t len, FILE *fp) {
return fgets(buf, (int)len, fp) != nullptr;
}
static bool readerInteractiveLine(char *buf, size_t len, FILE *__) {
return editline(len, buf);
}
[[gnu::nonnull]] void readerLoop(FILE *restrict fp) {
char input_buf[buf_size];
auto reader_fn = fp == stdin ? readerInteractiveLine : readRawLine;
while (reader_fn(input_buf, buf_size, fp)) [[clang::likely]]
procInput(input_buf);
}
void printElem(elem_t elem) {
switch (elem.rtype) {
case RTYPE_REAL:
printReal(elem.elem.real);
break;
case RTYPE_COMP:
print_complex(elem.elem.comp);
break;
case RTYPE_MATR:
printMatrix(elem.elem.matr);
break;
case RTYPE_LAMB:
printLambda(elem.elem.lamb);
break;
default:
[[clang::unlikely]];
}
}
void printReal(double result) {
if (result == (double)(long)result) PRINT("result: ", (long)result, "\n");
else PRINT("result: ", result, "\n");
}
void printComplexComplex(comp result) {
PRINT("result: ", creal(result), " + ", cimag(result), "i\n");
}
void printComplexPolar(comp result) {
comp res = result;
if (isnan(creal(res)) || isnan(cimag(res))) return;
PRINT(
"result: ", cabs(res), " \\phasor ", atan2(cimag(res), creal(res)), "\n"
);
}
void printMatrix(matrix_t result) {
for (size_t i = 0; i < result.rows; i++) {
for (size_t j = 0; j < result.cols; j++) {
comp res = result.matrix[result.cols * i + j];
putchar('\t');
if (eq(cimag(res), 0.0)) PRINT(creal(res));
else PRINT(creal(res), " + ", cimag(res), "i");
}
putchar('\n');
}
}
[[gnu::nonnull]] void printLambda(char const *result) {
PRINT("result: ", (char *)result, "\n");
}
[[gnu::nonnull]] void procCmds(char const *restrict cmd) {
plotcfg_t pcfg = getPlotCfg();
switch (*cmd++) {
case 't': switch (*cmd) {
case 'c': eval_f = eval_f == evalExprReal ? evalExprComplex : evalExprReal;
break;
case 'p': pcfg.plotexpr = pcfg.plotexpr == plotexpr ? plotexprImplicit : plotexpr;
setPlotCfg(pcfg);
break;
case 'P': print_complex = print_complex == printComplexComplex
? printComplexPolar
: printComplexComplex;
break;
default:
[[clang::unlikely]];
}
break;
case 'o': {
char buf[buf_size];
strncpy(buf, cmd, buf_size);
optexpr(buf);
puts(buf);
} break;
case 'p':
cmd += skipByte(cmd, ' ');
if (*cmd == '\0') {
plotexpr(pcfg.prevexpr);
break;
}
pcfg.plotexpr(cmd);
strncpy(pcfg.prevexpr, cmd, buf_size);
setPlotCfg(pcfg);
break;
case 'r': switch (*cmd) {
case 's': sxorsh((uint64_t)evalExprReal(cmd + 1).elem.real);
break;
default:
}
break;
case 's': switch (*cmd) {
case 'p': changePlotCfg(cmd + 1);
break;
default:
[[clang::unlikely]];
}
break;
default:
DISPERR("unknown command: ", *(cmd - 1));
}
}