mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-13 17:42:44 +08:00
![Kurtis Rader](/assets/img/avatar_default.png)
First step in fixing issue #3157 is to check-in the source code and hook it into our build system. The inclusion of the MuParser source adds the MIT License to those that apply to fish. Update our documentation to reflect that fact. The MuParser documentation is at http://beltoforion.de/article.php?a=muparser. The source was downloaded from https://github.com/beltoforion/muparser/releases. It is also hosted on Github, https://github.com/beltoforion/muparser/. I did not download it from Github because that source contained just a couple of cleanup changes which don't affect its behavior.
443 lines
13 KiB
C
443 lines
13 KiB
C
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <wchar.h>
|
|
|
|
#include "muParserDLL.h"
|
|
|
|
#define PARSER_CONST_PI 3.141592653589793238462643
|
|
#define PARSER_CONST_E 2.718281828459045235360287
|
|
#define PARSER_MAXVARS 10
|
|
|
|
#ifndef _UNICODE
|
|
#define _T(x) x
|
|
#define myprintf printf
|
|
#define mystrlen strlen
|
|
#define myfgets fgets
|
|
#define mystrcmp strcmp
|
|
#else
|
|
#define _T(x) L ##x
|
|
#define myprintf wprintf
|
|
#define mystrlen wcslen
|
|
#define myfgets fgetws
|
|
#define mystrcmp wcscmp
|
|
#endif
|
|
|
|
extern void CalcBulk();
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Callbacks for postfix operators
|
|
muFloat_t Mega(muFloat_t a_fVal)
|
|
{
|
|
return a_fVal * 1.0e6;
|
|
}
|
|
|
|
muFloat_t Milli(muFloat_t a_fVal)
|
|
{
|
|
return a_fVal / 1.0e3;
|
|
}
|
|
|
|
muFloat_t ZeroArg()
|
|
{
|
|
myprintf(_T("i'm a function without arguments.\n"));
|
|
return 123;
|
|
}
|
|
|
|
muFloat_t BulkTest(int nBulkIdx, int nThreadIdx, muFloat_t v1)
|
|
{
|
|
(void*)&nThreadIdx; // STFU compiler warning...
|
|
myprintf(_T("%d,%2.2f\n"), nBulkIdx, v1);
|
|
return v1 / (nBulkIdx + 1);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Callbacks for infix operators
|
|
muFloat_t Not(muFloat_t v) { return v == 0; }
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Function callbacks
|
|
muFloat_t Rnd(muFloat_t v) { return v * rand() / (muFloat_t)(RAND_MAX + 1.0); }
|
|
|
|
muFloat_t SampleQuery(const muChar_t *szMsg)
|
|
{
|
|
if (szMsg)
|
|
{
|
|
myprintf(_T("%s\n"), szMsg);
|
|
}
|
|
|
|
return 999;
|
|
}
|
|
|
|
muFloat_t Sum(const muFloat_t *a_afArg, int a_iArgc)
|
|
{
|
|
muFloat_t fRes = 0;
|
|
int i = 0;
|
|
|
|
for (i = 0; i < a_iArgc; ++i)
|
|
fRes += a_afArg[i];
|
|
|
|
return fRes;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Binarty operator callbacks
|
|
muFloat_t Add(muFloat_t v1, muFloat_t v2)
|
|
{
|
|
return v1 + v2;
|
|
}
|
|
|
|
muFloat_t Mul(muFloat_t v1, muFloat_t v2)
|
|
{
|
|
return v1*v2;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Factory function for creating new parser variables
|
|
// This could as well be a function performing database queries.
|
|
muFloat_t* AddVariable(const muChar_t* a_szName, void *pUserData)
|
|
{
|
|
static muFloat_t afValBuf[PARSER_MAXVARS]; // I don't want dynamic allocation here
|
|
static int iVal = 0; // so i used this buffer
|
|
|
|
myprintf(_T("Generating new variable \"%s\" (slots left: %d; context pointer: 0x%x)\n"), a_szName, PARSER_MAXVARS - iVal, (int)pUserData);
|
|
|
|
afValBuf[iVal] = 0;
|
|
if (iVal >= PARSER_MAXVARS - 1)
|
|
{
|
|
myprintf(_T("Variable buffer overflow."));
|
|
return NULL;
|
|
}
|
|
|
|
return &afValBuf[iVal++];
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void Intro(muParserHandle_t hParser)
|
|
{
|
|
myprintf(_T(" __________ \n"));
|
|
myprintf(_T(" _____ __ __\\______ \\_____ _______ ______ ____ _______\n"));
|
|
myprintf(_T(" / \\ | | \\| ___/\\__ \\ \\_ __ \\/ ___/_/ __ \\\\_ __ \\ \n"));
|
|
myprintf(_T(" | Y Y \\| | /| | / __ \\_| | \\/\\___ \\ \\ ___/ | | \\/ \n"));
|
|
myprintf(_T(" |__|_| /|____/ |____| (____ /|__| /____ > \\___ >|__| \n"));
|
|
myprintf(_T(" \\/ \\/ \\/ \\/ \n"));
|
|
myprintf(_T(" Version %s (DLL)\n"), mupGetVersion(hParser));
|
|
#ifdef _UNICODE
|
|
myprintf(_T(" Sample build with UNICODE support\n"));
|
|
#else
|
|
myprintf(_T(" Sample build with ASCII support\n"));
|
|
#endif
|
|
myprintf(_T(" (C) 2015 Ingo Berg\n"));
|
|
myprintf(_T("---------------------------------------\n"));
|
|
myprintf(_T("Commands:\n"));
|
|
myprintf(_T(" list var - list parser variables\n"));
|
|
myprintf(_T(" list exprvar - list expression variables\n"));
|
|
myprintf(_T(" list const - list all numeric parser constants\n"));
|
|
myprintf(_T(" locale de - switch to german locale\n"));
|
|
myprintf(_T(" locale en - switch to english locale\n"));
|
|
myprintf(_T(" locale reset - reset locale\n"));
|
|
myprintf(_T(" test bulk - test bulk mode\n"));
|
|
myprintf(_T(" quit - exits the parser\n\n"));
|
|
myprintf(_T("---------------------------------------\n"));
|
|
myprintf(_T("Constants:\n"));
|
|
myprintf(_T(" \"_e\" 2.718281828459045235360287\n"));
|
|
myprintf(_T(" \"_pi\" 3.141592653589793238462643\n"));
|
|
myprintf(_T("---------------------------------------\n"));
|
|
myprintf(_T("Please enter an expression:\n"));
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Callback function for parser errors
|
|
void OnError(muParserHandle_t hParser)
|
|
{
|
|
myprintf(_T("\nError:\n"));
|
|
myprintf(_T("------\n"));
|
|
myprintf(_T("Message: \"%s\"\n"), mupGetErrorMsg(hParser));
|
|
myprintf(_T("Token: \"%s\"\n"), mupGetErrorToken(hParser));
|
|
myprintf(_T("Position: %d\n"), mupGetErrorPos(hParser));
|
|
myprintf(_T("Errc: %d\n"), mupGetErrorCode(hParser));
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void ListVar(muParserHandle_t a_hParser)
|
|
{
|
|
int iNumVar = mupGetVarNum(a_hParser);
|
|
int i = 0;
|
|
|
|
if (iNumVar == 0)
|
|
{
|
|
myprintf(_T("No variables defined\n"));
|
|
return;
|
|
}
|
|
|
|
myprintf(_T("\nExpression variables:\n"));
|
|
myprintf(_T("---------------------\n"));
|
|
myprintf(_T("Number: %d\n"), iNumVar);
|
|
|
|
for (i = 0; i < iNumVar; ++i)
|
|
{
|
|
const muChar_t* szName = 0;
|
|
muFloat_t* pVar = 0;
|
|
|
|
mupGetVar(a_hParser, i, &szName, &pVar);
|
|
myprintf(_T("Name: %s Address: [0x%x]\n"), szName, (long long)pVar);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void ListExprVar(muParserHandle_t a_hParser)
|
|
{
|
|
muInt_t iNumVar = mupGetExprVarNum(a_hParser),
|
|
i = 0;
|
|
|
|
if (iNumVar == 0)
|
|
{
|
|
myprintf(_T("Expression dos not contain variables\n"));
|
|
return;
|
|
}
|
|
|
|
myprintf(_T("\nExpression variables:\n"));
|
|
myprintf(_T("---------------------\n"));
|
|
myprintf(_T("Expression: %s\n"), mupGetExpr(a_hParser));
|
|
myprintf(_T("Number: %d\n"), iNumVar);
|
|
|
|
for (i = 0; i < iNumVar; ++i)
|
|
{
|
|
const muChar_t* szName = 0;
|
|
muFloat_t* pVar = 0;
|
|
|
|
mupGetExprVar(a_hParser, i, &szName, &pVar);
|
|
myprintf(_T("Name: %s Address: [0x%x]\n"), szName, (long long)pVar);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void ListConst(muParserHandle_t a_hParser)
|
|
{
|
|
muInt_t iNumVar = mupGetConstNum(a_hParser),
|
|
i = 0;
|
|
|
|
if (iNumVar == 0)
|
|
{
|
|
myprintf(_T("No constants defined\n"));
|
|
return;
|
|
}
|
|
|
|
myprintf(_T("\nParser constants:\n"));
|
|
myprintf(_T("---------------------\n"));
|
|
myprintf(_T("Number: %d"), iNumVar);
|
|
|
|
for (i = 0; i < iNumVar; ++i)
|
|
{
|
|
const muChar_t* szName = 0;
|
|
muFloat_t fVal = 0;
|
|
|
|
mupGetConst(a_hParser, i, &szName, &fVal);
|
|
myprintf(_T(" %s = %f\n"), szName, fVal);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
/** \brief Check for external keywords.
|
|
*/
|
|
int CheckKeywords(const muChar_t *a_szLine, muParserHandle_t a_hParser)
|
|
{
|
|
if (!mystrcmp(a_szLine, _T("quit")))
|
|
{
|
|
return -1;
|
|
}
|
|
else if (!mystrcmp(a_szLine, _T("list var")))
|
|
{
|
|
ListVar(a_hParser);
|
|
return 1;
|
|
}
|
|
else if (!mystrcmp(a_szLine, _T("list exprvar")))
|
|
{
|
|
ListExprVar(a_hParser);
|
|
return 1;
|
|
}
|
|
else if (!mystrcmp(a_szLine, _T("list const")))
|
|
{
|
|
ListConst(a_hParser);
|
|
return 1;
|
|
}
|
|
else if (!mystrcmp(a_szLine, _T("locale de")))
|
|
{
|
|
myprintf(_T("Setting german locale: ArgSep=';' DecSep=',' ThousandsSep='.'\n"));
|
|
mupSetArgSep(a_hParser, ';');
|
|
mupSetDecSep(a_hParser, ',');
|
|
mupSetThousandsSep(a_hParser, '.');
|
|
return 1;
|
|
}
|
|
else if (!mystrcmp(a_szLine, _T("locale en")))
|
|
{
|
|
myprintf(_T("Setting english locale: ArgSep=',' DecSep='.' ThousandsSep=''\n"));
|
|
mupSetArgSep(a_hParser, ',');
|
|
mupSetDecSep(a_hParser, '.');
|
|
mupSetThousandsSep(a_hParser, 0);
|
|
return 1;
|
|
}
|
|
else if (!mystrcmp(a_szLine, _T("locale reset")))
|
|
{
|
|
myprintf(_T("Resetting locale\n"));
|
|
mupResetLocale(a_hParser);
|
|
return 1;
|
|
}
|
|
else if (!mystrcmp(a_szLine, _T("test bulk")))
|
|
{
|
|
myprintf(_T("Testing bulk mode\n"));
|
|
CalcBulk();
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void CalcBulk()
|
|
{
|
|
int nBulkSize = 200, i;
|
|
muFloat_t *x = (muFloat_t*)malloc(nBulkSize * sizeof(muFloat_t));
|
|
muFloat_t *y = (muFloat_t*)malloc(nBulkSize * sizeof(muFloat_t));
|
|
muFloat_t *r = (muFloat_t*)malloc(nBulkSize * sizeof(muFloat_t));
|
|
|
|
muParserHandle_t hParser = mupCreate(muBASETYPE_FLOAT); // initialize the parser
|
|
|
|
for (i = 0; i < nBulkSize; ++i)
|
|
{
|
|
x[i] = i;
|
|
y[i] = i;
|
|
r[i] = 0;
|
|
}
|
|
|
|
mupDefineVar(hParser, _T("x"), x);
|
|
mupDefineVar(hParser, _T("y"), y);
|
|
mupDefineBulkFun1(hParser, _T("bulktest"), BulkTest);
|
|
mupSetExpr(hParser, _T("bulktest(x+y)"));
|
|
mupEvalBulk(hParser, r, nBulkSize);
|
|
if (mupError(hParser))
|
|
{
|
|
myprintf(_T("\nError:\n"));
|
|
myprintf(_T("------\n"));
|
|
myprintf(_T("Message: %s\n"), mupGetErrorMsg(hParser));
|
|
myprintf(_T("Token: %s\n"), mupGetErrorToken(hParser));
|
|
myprintf(_T("Position: %d\n"), mupGetErrorPos(hParser));
|
|
myprintf(_T("Errc: %d\n"), mupGetErrorCode(hParser));
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < nBulkSize; ++i)
|
|
{
|
|
myprintf(_T("%d: bulkfun(%2.2f + %2.2f) = %2.2f\n"), i, x[i], y[i], r[i]);
|
|
x[i] = i;
|
|
y[i] = (muFloat_t)i / 10;
|
|
}
|
|
|
|
free(x);
|
|
free(y);
|
|
free(r);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void Calc()
|
|
{
|
|
muChar_t szLine[100];
|
|
muFloat_t fVal = 0,
|
|
afVarVal[] = { 1, 2 }; // Values of the parser variables
|
|
muParserHandle_t hParser;
|
|
|
|
hParser = mupCreate(muBASETYPE_FLOAT); // initialize the parser
|
|
Intro(hParser);
|
|
|
|
// Set an error handler [optional]
|
|
// the only function that does not take a parser instance handle
|
|
mupSetErrorHandler(hParser, OnError);
|
|
|
|
//#define GERMAN_LOCALS
|
|
#ifdef GERMAN_LOCALS
|
|
mupSetArgSep(hParser, ';');
|
|
mupSetDecSep(hParser, ',');
|
|
mupSetThousandsSep(hParser, '.');
|
|
#else
|
|
mupSetArgSep(hParser, ',');
|
|
mupSetDecSep(hParser, '.');
|
|
#endif
|
|
|
|
// Set a variable factory
|
|
mupSetVarFactory(hParser, AddVariable, NULL);
|
|
|
|
// Define parser variables and bind them to C++ variables [optional]
|
|
mupDefineConst(hParser, _T("const1"), 1);
|
|
mupDefineConst(hParser, _T("const2"), 2);
|
|
mupDefineStrConst(hParser, _T("strBuf"), _T("Hallo welt"));
|
|
|
|
// Define parser variables and bind them to C++ variables [optional]
|
|
mupDefineVar(hParser, _T("a"), &afVarVal[0]);
|
|
mupDefineVar(hParser, _T("b"), &afVarVal[1]);
|
|
|
|
// Define postfix operators [optional]
|
|
mupDefinePostfixOprt(hParser, _T("M"), Mega, 0);
|
|
mupDefinePostfixOprt(hParser, _T("m"), Milli, 0);
|
|
|
|
// Define infix operator [optional]
|
|
mupDefineInfixOprt(hParser, _T("!"), Not, 0);
|
|
|
|
// Define functions [optional]
|
|
// mupDefineStrFun(hParser, "query", SampleQuery, 0); // Add an unoptimizeable function
|
|
mupDefineFun0(hParser, _T("zero"), ZeroArg, 0);
|
|
mupDefineFun1(hParser, _T("rnd"), Rnd, 0); // Add an unoptimizeable function
|
|
mupDefineFun1(hParser, _T("rnd2"), Rnd, 1);
|
|
mupDefineMultFun(hParser, _T("_sum"), Sum, 0); // "sum" is already a default function
|
|
|
|
// Define binary operators [optional]
|
|
mupDefineOprt(hParser, _T("add"), Add, 0, muOPRT_ASCT_LEFT, 0);
|
|
mupDefineOprt(hParser, _T("mul"), Mul, 1, muOPRT_ASCT_LEFT, 0);
|
|
|
|
while (myfgets(szLine, 99, stdin))
|
|
{
|
|
szLine[mystrlen(szLine) - 1] = 0; // overwrite the newline
|
|
|
|
switch (CheckKeywords(szLine, hParser))
|
|
{
|
|
case 0: break; // no keyword found; parse the line
|
|
case 1: continue; // A Keyword was found do not parse the line
|
|
case -1: return; // abort the application
|
|
}
|
|
|
|
mupSetExpr(hParser, szLine);
|
|
|
|
fVal = mupEval(hParser);
|
|
|
|
|
|
// Without an Error handler function
|
|
// you must use this for error treatment:
|
|
//if (mupError(hParser))
|
|
//{
|
|
// printf("\nError:\n");
|
|
// printf("------\n");
|
|
// printf("Message: %s\n", mupGetErrorMsg(hParser) );
|
|
// printf("Token: %s\n", mupGetErrorToken(hParser) );
|
|
// printf("Position: %s\n", mupGetErrorPos(hParser) );
|
|
// printf("Errc: %d\n", mupGetErrorCode(hParser) );
|
|
// continue;
|
|
//}
|
|
|
|
if (!mupError(hParser))
|
|
myprintf(_T("%f\n"), fVal);
|
|
|
|
} // while
|
|
|
|
// finalle free the parser ressources
|
|
mupRelease(hParser);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
int main(int argc, char *argv[])
|
|
{
|
|
// The next line is just for shutting up the compiler warning
|
|
// about unused variables without getting another warning about not
|
|
// beeing able to use type lists in function declarations.
|
|
myprintf(_T("Executing \"%s\" (argc=%d)\n"), argv[0], argc);
|
|
Calc();
|
|
printf(_T("done..."));
|
|
}
|