cparse / cparse Goto Github PK
View Code? Open in Web Editor NEWA C++ configurable Expression Parser. Useful as a Calculator or for helping you write your own Programming Language
License: MIT License
A C++ configurable Expression Parser. Useful as a Calculator or for helping you write your own Programming Language
License: MIT License
If I follow the instructions under Getting Started / Setup, I get an error at the "Link with your project" stage. This happens on macOS and Linux. For main.cpp, I am using the example provided later under "Minimal examples".
The first problem is
$ g++ cparse/builtin-features.o cparse/core-shunting-yard.o main.cpp -o main
main.cpp:2:27: fatal error: shunting-yard.h: No such file or directory
because in the example, compilation happens outside the cparse directory, and cparse is not on the include path. Adding -Icparse to the command fixes this of course.
The next error is
$ g++ cparse/builtin-features.o cparse/core-shunting-yard.o main.cpp -o main -I cparse
In file included from main.cpp:2:0:
cparse/shunting-yard.h:23:9: error: ‘uint8_t’ does not name a type
typedef uint8_t tokType_t;
This is because uint8_t is a C++11 feature, and this compiler (g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16)), does not support C++11 by default. You need to add -std=c++11.
If I use
g++ -std=c++11 cparse/builtin-features.o cparse/core-shunting-yard.o main.cpp -o main -I cparse
it compiles fine. Should the command in the README be updated?
Hi again @VinGarcia ,
So i'm almost done with my project , really happy to have chosen cparse as the parser !
Since you have already done it for your own language , i'm trying to implement a simple if statement
IF(expression, value if true, value if false) i was thinking about implementing it as a function, but i don't how to go about and somewhat i have an intuition that there is a "correct" way to go about it.
thanks in advance you have been really helpful 👍 !
Currently we represent boolean types as C would, 0 means false, and != 0 means true.
This works and is not bad, but if our users want to have a BOOL type they would be forced to implement one themselfs, and that would be an unnecessary complication.
Since having a BOOL type is quite common in programming languages we should define a builtin one on our system.
I wrote a simple code example:
#include <iostream>
#include "shunting-yard.h"
int main() {
TokenMap vars;
calculator c1("v1 v2");
std::cout << c1.eval(vars) << std::endl; // outputs "v2"
return 0;
}
This prints "v2" and looks like it ignores v1 completely. I wonder why. I expected this expression would output a syntax error because of the omitted operator between v1 and v2. And this is also not two separate statements (as there is no ';' between them). What does this expression mean to the calculator?
Most of this is just pedantic grumbling, but the conversion from 'long' to 'const packToken' is ambiguous
error looks legit and is preventing it from compiling.
$ git clone https://github.com/cparse/cparse.git
Cloning into 'cparse'...
remote: Enumerating objects: 1134, done.
remote: Total 1134 (delta 0), reused 0 (delta 0), pack-reused 1134
Receiving objects: 100% (1134/1134), 509.58 KiB | 2.01 MiB/s, done.
Resolving deltas: 100% (776/776), done.
$ cd cparse; git rev-parse HEAD
a9f26860283c2653f8a0fcb003cbb07f21b690af
$ make
c++ -std=c++11 -Wall -pedantic -Wmissing-field-initializers -Wuninitialized -g -c test-shunting-yard.cpp -o test-shunting-yard.o -g
In file included from test-shunting-yard.cpp:6:
In file included from ././shunting-yard.h:155:
././containers.h:38:1: warning: 'Iterator' defined as a struct here but previously declared as a class
[-Wmismatched-tags]
struct Iterator : public Iterable {
^
././containers.h:27:1: note: did you mean struct here?
class Iterator;
^~~~~
struct
././containers.h:63:1: warning: 'TokenMap' defined as a struct here but previously declared as a class
[-Wmismatched-tags]
struct TokenMap : public Container<MapData_t>, public Iterable {
^
././containers.h:50:1: note: did you mean struct here?
class TokenMap;
^~~~~
struct
././shunting-yard.h:147:1: note: did you mean struct here?
class TokenMap;
^~~~~
struct
In file included from test-shunting-yard.cpp:6:
In file included from ././shunting-yard.h:155:
././containers.h:135:1: warning: 'TokenList' defined as a struct here but previously declared as a
class [-Wmismatched-tags]
struct TokenList : public Container<TokenList_t>, public Iterable {
^
././shunting-yard.h:148:1: note: did you mean struct here?
class TokenList;
^~~~~
struct
././shunting-yard.h:242:37: warning: 'const' qualifier on function type 'rWordParser_t' (aka 'void
(const char *, const char **, rpnBuilder *)') has no effect [-Wignored-qualifiers]
void add(const std::string& word, const rWordParser_t* parser) {
^~~~~~
././shunting-yard.h:247:20: warning: 'const' qualifier on function type 'rWordParser_t' (aka 'void
(const char *, const char **, rpnBuilder *)') has no effect [-Wignored-qualifiers]
void add(char c, const rWordParser_t* parser) {
^~~~~~
././shunting-yard.h:347:1: warning: 'opMap_t' defined as a struct here but previously declared as a
class [-Wmismatched-tags]
struct opMap_t : public std::map<std::string, opList_t> {
^
././shunting-yard.h:214:1: note: did you mean struct here?
class opMap_t;
^~~~~
struct
test-shunting-yard.cpp:925:26: error: conversion from 'long' to 'const packToken' is ambiguous
REQUIRE(c1.eval() == ~10l);
^~~~
./catch.hpp:10436:46: note: expanded from macro 'REQUIRE'
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
^~~~
./catch.hpp:2076:41: note: expanded from macro 'INTERNAL_CATCH_TEST'
} while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime bu...
^~~~
././packToken.h:25:3: note: candidate constructor
packToken(int i) : base(new Token<int64_t>(i, INT)) {}
^
././packToken.h:26:3: note: candidate constructor
packToken(int64_t l) : base(new Token<int64_t>(l, INT)) {}
^
././packToken.h:27:3: note: candidate constructor
packToken(bool b) : base(new Token<uint8_t>(b, BOOL)) {}
^
././packToken.h:28:3: note: candidate constructor
packToken(size_t s) : base(new Token<int64_t>(s, INT)) {}
^
././packToken.h:29:3: note: candidate constructor
packToken(float f) : base(new Token<double>(f, REAL)) {}
^
././packToken.h:30:3: note: candidate constructor
packToken(double d) : base(new Token<double>(d, REAL)) {}
^
test-shunting-yard.cpp:928:28: error: conversion from 'long' to 'const packToken' is ambiguous
REQUIRE(c1.eval() == 2 * ~10l);
~~^~~~~~
./catch.hpp:10436:46: note: expanded from macro 'REQUIRE'
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
^~~~
./catch.hpp:2076:41: note: expanded from macro 'INTERNAL_CATCH_TEST'
} while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime bu...
^~~~
././packToken.h:25:3: note: candidate constructor
packToken(int i) : base(new Token<int64_t>(i, INT)) {}
^
././packToken.h:26:3: note: candidate constructor
packToken(int64_t l) : base(new Token<int64_t>(l, INT)) {}
^
././packToken.h:27:3: note: candidate constructor
packToken(bool b) : base(new Token<uint8_t>(b, BOOL)) {}
^
././packToken.h:28:3: note: candidate constructor
packToken(size_t s) : base(new Token<int64_t>(s, INT)) {}
^
././packToken.h:29:3: note: candidate constructor
packToken(float f) : base(new Token<double>(f, REAL)) {}
^
././packToken.h:30:3: note: candidate constructor
packToken(double d) : base(new Token<double>(d, REAL)) {}
^
test-shunting-yard.cpp:931:28: error: conversion from 'long' to 'const packToken' is ambiguous
REQUIRE(c1.eval() == 2 * ~(10l*3));
~~^~~~~~~~~~
./catch.hpp:10436:46: note: expanded from macro 'REQUIRE'
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
^~~~
./catch.hpp:2076:41: note: expanded from macro 'INTERNAL_CATCH_TEST'
} while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime bu...
^~~~
././packToken.h:25:3: note: candidate constructor
packToken(int i) : base(new Token<int64_t>(i, INT)) {}
^
././packToken.h:26:3: note: candidate constructor
packToken(int64_t l) : base(new Token<int64_t>(l, INT)) {}
^
././packToken.h:27:3: note: candidate constructor
packToken(bool b) : base(new Token<uint8_t>(b, BOOL)) {}
^
././packToken.h:28:3: note: candidate constructor
packToken(size_t s) : base(new Token<int64_t>(s, INT)) {}
^
././packToken.h:29:3: note: candidate constructor
packToken(float f) : base(new Token<double>(f, REAL)) {}
^
././packToken.h:30:3: note: candidate constructor
packToken(double d) : base(new Token<double>(d, REAL)) {}
^
test-shunting-yard.cpp:964:26: error: conversion from 'long' to 'const packToken' is ambiguous
REQUIRE(c1.eval() == ~10l);
^~~~
./catch.hpp:10436:46: note: expanded from macro 'REQUIRE'
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
^~~~
./catch.hpp:2076:41: note: expanded from macro 'INTERNAL_CATCH_TEST'
} while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime bu...
^~~~
././packToken.h:25:3: note: candidate constructor
packToken(int i) : base(new Token<int64_t>(i, INT)) {}
^
././packToken.h:26:3: note: candidate constructor
packToken(int64_t l) : base(new Token<int64_t>(l, INT)) {}
^
././packToken.h:27:3: note: candidate constructor
packToken(bool b) : base(new Token<uint8_t>(b, BOOL)) {}
^
././packToken.h:28:3: note: candidate constructor
packToken(size_t s) : base(new Token<int64_t>(s, INT)) {}
^
././packToken.h:29:3: note: candidate constructor
packToken(float f) : base(new Token<double>(f, REAL)) {}
^
././packToken.h:30:3: note: candidate constructor
packToken(double d) : base(new Token<double>(d, REAL)) {}
^
test-shunting-yard.cpp:967:26: error: conversion from 'long' to 'const packToken' is ambiguous
REQUIRE(c1.eval() == ~(2*10l));
^~~~~~~~
./catch.hpp:10436:46: note: expanded from macro 'REQUIRE'
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
^~~~
./catch.hpp:2076:41: note: expanded from macro 'INTERNAL_CATCH_TEST'
} while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime bu...
^~~~
././packToken.h:25:3: note: candidate constructor
packToken(int i) : base(new Token<int64_t>(i, INT)) {}
^
././packToken.h:26:3: note: candidate constructor
packToken(int64_t l) : base(new Token<int64_t>(l, INT)) {}
^
././packToken.h:27:3: note: candidate constructor
packToken(bool b) : base(new Token<uint8_t>(b, BOOL)) {}
^
././packToken.h:28:3: note: candidate constructor
packToken(size_t s) : base(new Token<int64_t>(s, INT)) {}
^
././packToken.h:29:3: note: candidate constructor
packToken(float f) : base(new Token<double>(f, REAL)) {}
^
././packToken.h:30:3: note: candidate constructor
packToken(double d) : base(new Token<double>(d, REAL)) {}
^
test-shunting-yard.cpp:970:35: error: conversion from 'long' to 'const packToken' is ambiguous
REQUIRE(c1.eval() == ~(2*10l) * 3);
~~~~~~~~~^~~
./catch.hpp:10436:46: note: expanded from macro 'REQUIRE'
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
^~~~
./catch.hpp:2076:41: note: expanded from macro 'INTERNAL_CATCH_TEST'
} while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime bu...
^~~~
././packToken.h:25:3: note: candidate constructor
packToken(int i) : base(new Token<int64_t>(i, INT)) {}
^
././packToken.h:26:3: note: candidate constructor
packToken(int64_t l) : base(new Token<int64_t>(l, INT)) {}
^
././packToken.h:27:3: note: candidate constructor
packToken(bool b) : base(new Token<uint8_t>(b, BOOL)) {}
^
././packToken.h:28:3: note: candidate constructor
packToken(size_t s) : base(new Token<int64_t>(s, INT)) {}
^
././packToken.h:29:3: note: candidate constructor
packToken(float f) : base(new Token<double>(f, REAL)) {}
^
././packToken.h:30:3: note: candidate constructor
packToken(double d) : base(new Token<double>(d, REAL)) {}
^
test-shunting-yard.cpp:974:26: error: conversion from 'long' to 'const packToken' is ambiguous
REQUIRE(c1.eval() == ~10l);
^~~~
./catch.hpp:10436:46: note: expanded from macro 'REQUIRE'
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
^~~~
./catch.hpp:2076:41: note: expanded from macro 'INTERNAL_CATCH_TEST'
} while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime bu...
^~~~
././packToken.h:25:3: note: candidate constructor
packToken(int i) : base(new Token<int64_t>(i, INT)) {}
^
././packToken.h:26:3: note: candidate constructor
packToken(int64_t l) : base(new Token<int64_t>(l, INT)) {}
^
././packToken.h:27:3: note: candidate constructor
packToken(bool b) : base(new Token<uint8_t>(b, BOOL)) {}
^
././packToken.h:28:3: note: candidate constructor
packToken(size_t s) : base(new Token<int64_t>(s, INT)) {}
^
././packToken.h:29:3: note: candidate constructor
packToken(float f) : base(new Token<double>(f, REAL)) {}
^
././packToken.h:30:3: note: candidate constructor
packToken(double d) : base(new Token<double>(d, REAL)) {}
^
test-shunting-yard.cpp:977:28: error: conversion from 'long' to 'const packToken' is ambiguous
REQUIRE(c1.eval() == 2 * ~10l);
~~^~~~~~
./catch.hpp:10436:46: note: expanded from macro 'REQUIRE'
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
^~~~
./catch.hpp:2076:41: note: expanded from macro 'INTERNAL_CATCH_TEST'
} while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime bu...
^~~~
././packToken.h:25:3: note: candidate constructor
packToken(int i) : base(new Token<int64_t>(i, INT)) {}
^
././packToken.h:26:3: note: candidate constructor
packToken(int64_t l) : base(new Token<int64_t>(l, INT)) {}
^
././packToken.h:27:3: note: candidate constructor
packToken(bool b) : base(new Token<uint8_t>(b, BOOL)) {}
^
././packToken.h:28:3: note: candidate constructor
packToken(size_t s) : base(new Token<int64_t>(s, INT)) {}
^
././packToken.h:29:3: note: candidate constructor
packToken(float f) : base(new Token<double>(f, REAL)) {}
^
././packToken.h:30:3: note: candidate constructor
packToken(double d) : base(new Token<double>(d, REAL)) {}
^
test-shunting-yard.cpp:980:35: error: conversion from 'long' to 'const packToken' is ambiguous
REQUIRE(c1.eval() == 2 * ~10l * 3);
~~~~~~~~~^~~
./catch.hpp:10436:46: note: expanded from macro 'REQUIRE'
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
^~~~
./catch.hpp:2076:41: note: expanded from macro 'INTERNAL_CATCH_TEST'
} while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime bu...
^~~~
././packToken.h:25:3: note: candidate constructor
packToken(int i) : base(new Token<int64_t>(i, INT)) {}
^
././packToken.h:26:3: note: candidate constructor
packToken(int64_t l) : base(new Token<int64_t>(l, INT)) {}
^
././packToken.h:27:3: note: candidate constructor
packToken(bool b) : base(new Token<uint8_t>(b, BOOL)) {}
^
././packToken.h:28:3: note: candidate constructor
packToken(size_t s) : base(new Token<int64_t>(s, INT)) {}
^
././packToken.h:29:3: note: candidate constructor
packToken(float f) : base(new Token<double>(f, REAL)) {}
^
././packToken.h:30:3: note: candidate constructor
packToken(double d) : base(new Token<double>(d, REAL)) {}
^
test-shunting-yard.cpp:984:35: error: conversion from 'long' to 'const packToken' is ambiguous
REQUIRE(c1.eval() == 2 * ~10l * 3);
~~~~~~~~~^~~
./catch.hpp:10436:46: note: expanded from macro 'REQUIRE'
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
^~~~
./catch.hpp:2076:41: note: expanded from macro 'INTERNAL_CATCH_TEST'
} while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime bu...
^~~~
././packToken.h:25:3: note: candidate constructor
packToken(int i) : base(new Token<int64_t>(i, INT)) {}
^
././packToken.h:26:3: note: candidate constructor
packToken(int64_t l) : base(new Token<int64_t>(l, INT)) {}
^
././packToken.h:27:3: note: candidate constructor
packToken(bool b) : base(new Token<uint8_t>(b, BOOL)) {}
^
././packToken.h:28:3: note: candidate constructor
packToken(size_t s) : base(new Token<int64_t>(s, INT)) {}
^
././packToken.h:29:3: note: candidate constructor
packToken(float f) : base(new Token<double>(f, REAL)) {}
^
././packToken.h:30:3: note: candidate constructor
packToken(double d) : base(new Token<double>(d, REAL)) {}
^
test-shunting-yard.cpp:987:35: error: conversion from 'long' to 'const packToken' is ambiguous
REQUIRE(c1.eval() == ~(2*10l) * 3);
~~~~~~~~~^~~
./catch.hpp:10436:46: note: expanded from macro 'REQUIRE'
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
^~~~
./catch.hpp:2076:41: note: expanded from macro 'INTERNAL_CATCH_TEST'
} while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime bu...
^~~~
././packToken.h:25:3: note: candidate constructor
packToken(int i) : base(new Token<int64_t>(i, INT)) {}
^
././packToken.h:26:3: note: candidate constructor
packToken(int64_t l) : base(new Token<int64_t>(l, INT)) {}
^
././packToken.h:27:3: note: candidate constructor
packToken(bool b) : base(new Token<uint8_t>(b, BOOL)) {}
^
././packToken.h:28:3: note: candidate constructor
packToken(size_t s) : base(new Token<int64_t>(s, INT)) {}
^
././packToken.h:29:3: note: candidate constructor
packToken(float f) : base(new Token<double>(f, REAL)) {}
^
././packToken.h:30:3: note: candidate constructor
packToken(double d) : base(new Token<double>(d, REAL)) {}
^
test-shunting-yard.cpp:990:35: error: conversion from 'long' to 'const packToken' is ambiguous
REQUIRE(c1.eval() == ~(2*10l) * 3);
~~~~~~~~~^~~
./catch.hpp:10436:46: note: expanded from macro 'REQUIRE'
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
^~~~
./catch.hpp:2076:41: note: expanded from macro 'INTERNAL_CATCH_TEST'
} while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime bu...
^~~~
././packToken.h:25:3: note: candidate constructor
packToken(int i) : base(new Token<int64_t>(i, INT)) {}
^
././packToken.h:26:3: note: candidate constructor
packToken(int64_t l) : base(new Token<int64_t>(l, INT)) {}
^
././packToken.h:27:3: note: candidate constructor
packToken(bool b) : base(new Token<uint8_t>(b, BOOL)) {}
^
././packToken.h:28:3: note: candidate constructor
packToken(size_t s) : base(new Token<int64_t>(s, INT)) {}
^
././packToken.h:29:3: note: candidate constructor
packToken(float f) : base(new Token<double>(f, REAL)) {}
^
././packToken.h:30:3: note: candidate constructor
packToken(double d) : base(new Token<double>(d, REAL)) {}
^
In file included from test-shunting-yard.cpp:4:
./catch.hpp:1336:44: error: conversion from 'long' to 'const packToken' is ambiguous
return bool( opCast( lhs ) == opCast( rhs ) );
^~~~~~~~~~~~~
./catch.hpp:1381:39: note: in instantiation of member function 'Catch::Internal::Evaluator<packToken,
long, Catch::Internal::Operator::IsEqualTo>::evaluate' requested here
return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
^
./catch.hpp:1874:39: note: in instantiation of function template specialization
'Catch::Internal::compare<Catch::Internal::Operator::IsEqualTo, packToken, long>' requested here
.setResultType( Internal::compare<Op>( m_lhs, rhs ) )
^
./catch.hpp:1817:16: note: in instantiation of function template specialization
'Catch::ExpressionLhs<const packToken &>::captureExpression<Catch::Internal::Operator::IsEqualTo,
long>' requested here
return captureExpression<Internal::IsEqualTo>( rhs );
^
test-shunting-yard.cpp:925:23: note: in instantiation of function template specialization
'Catch::ExpressionLhs<const packToken &>::operator==<long>' requested here
REQUIRE(c1.eval() == ~10l);
^
././packToken.h:25:3: note: candidate constructor
packToken(int i) : base(new Token<int64_t>(i, INT)) {}
^
././packToken.h:26:3: note: candidate constructor
packToken(int64_t l) : base(new Token<int64_t>(l, INT)) {}
^
././packToken.h:27:3: note: candidate constructor
packToken(bool b) : base(new Token<uint8_t>(b, BOOL)) {}
^
././packToken.h:28:3: note: candidate constructor
packToken(size_t s) : base(new Token<int64_t>(s, INT)) {}
^
././packToken.h:29:3: note: candidate constructor
packToken(float f) : base(new Token<double>(f, REAL)) {}
^
././packToken.h:30:3: note: candidate constructor
packToken(double d) : base(new Token<double>(d, REAL)) {}
^
6 warnings and 13 errors generated.
make: *** [test-shunting-yard.o] Error 1
Compiler:
$ clang -v
Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin15.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Hi again,
Until now i had to define the different data types and function i was going to use and everything is working great. The data we handle can be pretty big so in our framework we never load anything in memory unless we are using it, so we use files/database which means reads and writes. The reading part is all done, data is transferred and handled by the parser. Now the writing part : i need to be able to write my own assignment operator to add some data handling specific to our codebase and of course to write the results on drive.
So first i thought it was an operator i had to write, but since the operator is expecting a specific signature, with const refs to the operands, i figured it's definitely not the route to go. I checked the keyword page on the wiki and i think that defining the = as a key character is the solution. But i'm not really sure how to go about it and i'm not really sure because i want to make a version specific to my types no to all possible assignments.
i hope you can put me on the correct way to go about it , thank you again for you help !
The error messages were not a priority until now. But it is the moment to fix them.
We have currently 2 major problems:
The calculator should count how many new line characters have been parsed, and keep it as an available variable while compiling and evaluating as well.
Link in "As a sub-parser for a programming language." section of README.md file to "jSpy programming language" raises 404 error.
I suggest adding namespace around the cparse code.
(May be useful as I had name conflicts when I was adding cparse to my project, probably other devs might have as well)
For Ubuntu I followed your Linux setup guide and when I compile the code this is the error given:
https://pastebin.com/nhBt5KPX
Then I tried on VS Code but I can't compile there too, and it give me this error:
https://pastebin.com/SUE7UgbA
The VS Code "task.json" for compiling is the following:
{ "version": "2.0.0", "tasks": [ { "type": "cppbuild", "label": "C/C++: g++.exe compila il file attivo", "command": "C:\\msys64\\mingw64\\bin\\g++.exe", "args": [ "-std=c++11", "-fdiagnostics-color=always", "-g", "${file}", "-o", "${fileDirname}\\${fileBasenameNoExtension}.exe" ], "options": { "cwd": "${fileDirname}" }, "problemMatcher": [ "$gcc" ], "group": { "kind": "build", "isDefault": true }, "detail": "compilatore: C:\\msys64\\mingw64\\bin\\g++.exe" } ] }
I don't know if I'm dumb and I'm doing something wrong but I can't figure out how to fix even if I read the issue #55 and the other one about the same problem.
Sorry for the disturb and I appreciate if you can help me
My application is pre-compiling symbolic expressions in calculator
instances and then repeatedly eval'ing them at runtime. Obviously, the compilation stage allocates lots of TokenXX objects as it builds up the RPN list, but it looks like it then goes ahead and allocates essentially a parallel set on each evaluation:
Lines 494 to 502 in a9f2686
For an application where memory allocation (or at least syscalls) need to be avoided at runtime, it'd be great to have the expression evaluator able to work without making new allocations (or perhaps with the option of a pre-allocated value stack for the RPN engine).
Hi i did not know how to name the issue but here is an explanation :
My goal is to be able to write this :
W("name1").L("name2")
I have done this the way i wanted to with different classes, next i have to implement different operations possible between my classes. My issue is when using operators , when i write :
W("name1").L("name2") + W("name1").L("name3")
it tries to add the data returned by the expression on the left to the function W (and i'm trying to make add up the two results) , of course when i put the brackets around the second expression it works fine, but i want to force the parser to evaluate the whole expression without putting the brackets.
thanks in advance !
After writing the Wiki about Defining New Operations I realized that it is overly complicated.
The mask concept makes it hard to explain, and harder to understand the code.
We might still keep the mask concept, but if we do so, the user should not be exposed to it.
For example if instead of making a function that returns a mask, we make a function that returns only the type of the left operand and other for the right operand, and then we create the mask our selfs inside the Operation class constructor for example.
It should not be difficult to implement, but I might not have the time to do it. Also there is the problem of considering all the trade offs, and other possible ways to define it.
Anyway, the way it is it's complicated, we should think about it, and change it in the future.
hi great job,
but my output window is filled with all these warnings, can this be fixed, thank you.
1>C:\cparse\containers.h(38,17): warning C4099: 'Iterator': type name first seen using 'class' now seen using 'struct'
1>C:\cparse\containers.h(38): message : see declaration of 'Iterator'
1>C:\cparse\containers.h(64,17): warning C4099: 'TokenMap': type name first seen using 'class' now seen using 'struct'
1>C:\cparse\containers.h(64): message : see declaration of 'TokenMap'
1>C:\cparse\containers.h(136,18): warning C4099: 'TokenList': type name first seen using 'class' now seen using 'struct'
1>C:\cparse\containers.h(136): message : see declaration of 'TokenList'
1>C:\cparse\shunting-yard.h(348,16): warning C4099: 'opMap_t': type name first seen using 'class' now seen using 'struct'
I have some funky token identifiers in my language. (e.g. the 'ł', '€' and 'ð' characters), but this results in syntax errors. I assume this is because token identifiers only support ASCII characters.
Hi , i want to use this parser in a project we are currently working on.
We are developing on windows and use visual studio, i have always been the IDE guy so i have no idea how makefiles work i tried to create a project adding the files (following my understanding of the makefile - yes i did some reading on makefiles-) but i can't get it to work.
if i understand correctly , there are 2 libraries one is core and the second is the builtin fuctions so i need to create the first .lib file using the files of the core, then compile the built-in-features library that is dependent on the core one.
and of course there is the testing file.
i hope it's not too much to ask, i really like the project and it fits perfectly for my needs specially the fact that i can augment it with my own features.
Thank you in advance.
When compiling on macOS, I get
$ make release -C cparse
...
ld -r -O1 shunting-yard.o packToken.o functions.o containers.o -o core-shunting-yard.o
ld: unknown option: -O1
because -O1 is not a valid option to the macOS (BSD) linker. I've not come across the -O flag at link time before; is it necessary here? It seems to be gcc-specific. I'd just drop it for simplicity and portability if it's not really necessary.
This could be defined in LDFLAGS in the Makefile, which would allow the user to override LDFLAGS to either add or remove the -O1 option depending on whether you decided to keep it or not.
I was trying to use cparse in multi threaded application as a expression evaluator and varriable manager. I had to use static mutex in packToken class to ensure thread safety, the performance obviously took a hit. Is there a better way to do this?
Thanks
Hi, cparse is work pretty well on Linux. But when I compile it by MinGW on Windows, the high 32 bits of numbers is allways 0.
It seems long int strtol(...)
function return 32-bit integer, rather than 64-bit integer on MinGW/Windows, because of the data model of Windows is LLP.
related code:
// If the token is a number, add it to the output queue.
int64_t _int;
_int = strtol(expr, &nextChar, 10);
Maybe the strtoll()
is better?
Lack of proper forwarding is causing packToken(const packToken&) to be called instead of packToken(packToken&&), given this, the destructor of the local pass in arguments was also not being c
valgrind:memcheck 387,960 bytes in 16,165 blocks are definitely lost in loss record 261 of 267
valgrind:memcheck at 0x4C2A203: operator new(unsigned long) (vg_replace_malloc.c:334)
valgrind:memcheck by 0x1D7FD5A: Token::clone() const (shunting-yard.h:71)
valgrind:memcheck by 0x1D67CB9: RefToken::RefToken(packToken, TokenBase*, packToken) (shunting-yard.h:285)
How can cparse be compiled by Visual Studio in Windows Environment?
Hi, so i'm having an issue that i can't really figure out i'm using a list to store a BIG array of doubles so the copying goes fine, but once in my assignment function i write the same data on file then exit the function BUT the program won't go out and keeps calling the List destructor. i've tried letting it do it for hours and still the same issue it never get out of it.
Hello.
This simple piece of code causes a crash due to an error in the provided expression. The text "Some error" never gets printed.
#include <cparse/shunting-yard.h>
int main()
{
TokenMap tm;
tm["x"] = 5;
try
{
calculator calc;
calc.compile("5&&&x"); // I would expect this to throw an error, or set some flag I could check
printf("%f", calc.eval(tm).asDouble());
}
catch (...)
{
puts("Some error");
}
}
Changing the expression to e.g. 5*x
makes it print the correct result.
This is very unfortunate, since I expect the users of my application to be notified of an error if they input an invalid expression. Is there anything I'm doing wrong or is there any other mechanism for validating the expression?
I'm compiling with gcc on 64-bit MinGW. Everything links successfully.
g++ -std=c++11 main.cpp -I../includes ../libs/cparse/core-shunting-yard.o ../libs/cparse/my-features.o
Also setting the expression to e.g. 5x
does not crash the application, but doesn't throw errors either. It evaluates to x, though. However, setting it to sin(5x)
does crash it. sin(5*x)
works correctly.
The crash kind of looks like a stack overflow to me. Perhaps these expressions cause infinite recursion somewhere in the code?
Now, I have defined a custom function (logarithm) and a custom operator (caret for exponentiation). Those work and I don't think they have anything to do with this problem, but it's worth mentioning anyway.
Is it possible to create operators from alphabetic characters i.e. "and", "or", "like"?
LValues are Left Values in an assignment, e.g.: a = b
, i.e. the values that are linked to a named variable.
Currently, there is only one operation that changes the value of a variable and that is the assignment operator =
.
An example of another custom operator that changes the value of a variable is the increment and decrement operators of C++, e.g.: a++
and a--
. These are not yet possible using CParse.
So, this issue consists of:
This would allow us to create the ++
operator and also to change the default assignment operator to something different than =
, e.g.: <-
or :=
.
Hi,
The following unary expressions break:
Expr '3 * -4' -> -4
Expr '3 / -4' -> inf
Expr '3 - -4' -> -1
Expr '3 + -4' -> -1
Code used is very basic:
#include <iostream>
#include "shunting-yard.h"
int main(int argc, char* argv[])
{
TokenMap vars;
vars["pi"] = 3.14;
std::string str;
for (int idx = 1; idx < argc; ++idx) {
if (idx > 1)
str += ' ';
str += argv[idx];
}
std::cout << "Expr: '" << str << "'\n";
std::cout << calculator::calculate(str.c_str(), &vars) << std::endl;
return 0;
}
It seems rpnBuilder::handle_unary()
is not creating the correct RPN output for the above cases; debugged RPN output of the above show:
compile: '3 * -4'
RPN: TokenINT(3) TokenINT(0) TokenOP(*) TokenINT(4) TokenOP(-)
compile: '3 / -4'
RPN: TokenINT(3) TokenINT(0) TokenOP(/) TokenINT(4) TokenOP(-)
compile: '3 + -4'
RPN: TokenINT(3) TokenINT(0) TokenOP(+) TokenINT(4) TokenOP(-)
compile: '3 - -4'
RPN: TokenINT(3) TokenINT(0) TokenOP(-) TokenINT(4) TokenOP(-)
Followed the directions fore getting started; compiles fine but when running I'm getting this error:
terminating with uncaught exception of type syntax_error: Invalid operator: -
File: main.cpp
#include <iostream>
#include "shunting-yard.h"
int main() {
TokenMap vars;
vars["pi"] = 3.14;
std::cout << calculator::calculate("-pi+1", &vars) << std::endl;
return 0;
}
All my expressions (on Windows) throw the "Invalid operator" exception and I can't figure out why. Here's the error:
`C:\msys64\mingw64\bin\g++.exe -fdiagnostics-color=always -g C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\Pseudo.cpp -o C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\Pseudo.exe
In file included from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\cparse/builtin-features.inc:27,
from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\Pseudo.cpp:43:
C:/Users/Jg_747/iCloudDrive/Desktop/Progetti/Pseudo/Current/cparse/builtin-features/functions.inc: In function 'cparse::packToken builtin_functions::default_type(cparse::TokenMap)':
C:/Users/Jg_747/iCloudDrive/Desktop/Progetti/Pseudo/Current/cparse/builtin-features/functions.inc:104:8: error: reference to 'INT' is ambiguous
104 | case INT: return "integer";
| ^~~
In file included from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\Pseudo.cpp:38:
C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\cparse/shunting-yard.h:38:3: note: candidates are: 'cparse::tokType cparse::INT'
38 | INT = 0x22, // == 0x20 + 0x2 => Integral numbers.
| ^~~
In file included from C:/msys64/mingw64/x86_64-w64-mingw32/include/minwindef.h:163,
from C:/msys64/mingw64/x86_64-w64-mingw32/include/windef.h:9,
from C:/msys64/mingw64/x86_64-w64-mingw32/include/windows.h:69,
from C:/msys64/mingw64/x86_64-w64-mingw32/include/rpc.h:16,
from C:/msys64/mingw64/x86_64-w64-mingw32/include/urlmon.h:7,
from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\Pseudo.cpp:35:
C:/msys64/mingw64/x86_64-w64-mingw32/include/winnt.h:289:15: note: 'typedef int INT'
289 | typedef int INT;
| ^~~
In file included from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\cparse/builtin-features.inc:27,
from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\Pseudo.cpp:43:
C:/Users/Jg_747/iCloudDrive/Desktop/Progetti/Pseudo/Current/cparse/builtin-features/functions.inc:105:8: error: reference to 'BOOL' is ambiguous
105 | case BOOL: return "boolean";
| ^~~~
In file included from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\Pseudo.cpp:38:
C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\cparse/shunting-yard.h:39:3: note: candidates are: 'cparse::tokType cparse::BOOL'
39 | BOOL = 0x23, // == 0x20 + 0x3 => Boolean Type.
| ^~~~
In file included from C:/msys64/mingw64/x86_64-w64-mingw32/include/windef.h:9,
from C:/msys64/mingw64/x86_64-w64-mingw32/include/windows.h:69,
from C:/msys64/mingw64/x86_64-w64-mingw32/include/rpc.h:16,
from C:/msys64/mingw64/x86_64-w64-mingw32/include/urlmon.h:7,
from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\Pseudo.cpp:35:
C:/msys64/mingw64/x86_64-w64-mingw32/include/minwindef.h:131:15: note: 'typedef int BOOL'
131 | typedef int BOOL;
| ^~~~
In file included from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\cparse/builtin-features.inc:29,
from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\Pseudo.cpp:43:
C:/Users/Jg_747/iCloudDrive/Desktop/Progetti/Pseudo/Current/cparse/builtin-features/operations.inc: In constructor 'builtin_operations::Startup::Startup()':
C:/Users/Jg_747/iCloudDrive/Desktop/Progetti/Pseudo/Current/cparse/builtin-features/operations.inc:362:28: error: reference to 'BOOL' is ambiguous
362 | opMap.add({UNARY, "!", BOOL}, &UnaryNotOperation);
| ^~~~
In file included from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\Pseudo.cpp:38:
C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\cparse/shunting-yard.h:39:3: note: candidates are: 'cparse::tokType cparse::BOOL'
39 | BOOL = 0x23, // == 0x20 + 0x3 => Boolean Type.
| ^~~~
In file included from C:/msys64/mingw64/x86_64-w64-mingw32/include/windef.h:9,
from C:/msys64/mingw64/x86_64-w64-mingw32/include/windows.h:69,
from C:/msys64/mingw64/x86_64-w64-mingw32/include/rpc.h:16,
from C:/msys64/mingw64/x86_64-w64-mingw32/include/urlmon.h:7,
from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\Pseudo.cpp:35:
C:/msys64/mingw64/x86_64-w64-mingw32/include/minwindef.h:131:15: note: 'typedef int BOOL'
131 | typedef int BOOL;
| ^~~~
In file included from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\cparse/builtin-features.inc:29,
from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\Pseudo.cpp:43:
C:/Users/Jg_747/iCloudDrive/Desktop/Progetti/Pseudo/Current/cparse/builtin-features/operations.inc:362:14: error: cannot convert '' to 'cparse::opSignature_t'
362 | opMap.add({UNARY, "!", BOOL}, &UnaryNotOperation);
| ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\Pseudo.cpp:38:
C:\Users\Jg_747\iCloudDrive\Desktop\Progetti\Pseudo\Current\cparse/shunting-yard.h:360:32: note: initializing argument 1 of 'void cparse::opMap_t::add(cparse::opSignature_t, cparse::Operation::opFunc_t)'
360 | void add(const opSignature_t sig, Operation::opFunc_t func) {
| ~~~~~~~~~~~~~~~~~~~~^~~
La compilazione è terminata con errore/i.`
Currently we use a reference counting system for garbage collecting. I think it is specially efficient with the current architecture because we only need to manage the objects and lists, avoiding the worse part of the draw back of incrementing and decrementing the counter too often.
But there is still a problem to concern, namely the reference counting mechanism can not delete structures if they have cyclic reference among them, because it implies that each of them will always have ate least 1 reference, and thus can never be safely delocated.
We should think about how to fix it. I bet JavaScript uses reference counting since our engine seems to be very similar to theirs, and they have for sure found a solution. Another language I know uses reference counting is Python, and we could probably learn something from them as well.
The variable names: None, False and True are hard-coded to their respective values inside the calculator class. We should fix this and add them as global variables instead.
hi.
In MFC defined type BOOL. But cparser redefines identifier BOOL in shunting-yard.h at line 37.
I don't know what i do now. I can't change MFC BOOL. May be change BOOL in shunting-yard.h?
Do you have solution?
Currently we allow our users to define custom binary operators, but not unary.
Since this is a very basic concept we should handle this sometime soon.
The current TokenMap class uses the std::map implementation. This map is alright but if you try to iterate over it, e.g.:
TokenMap vars;
calculator::calculate("a = map('c': 1, 'b': 2, 'a': 3)", vars);
std::cout << vars["a"] << std::endl; // { 'a': 3, 'b': 2, 'c': 1 } (alphanumerical order)
It shows the keys in alphanumerical order instead of the insertion order. This is undesired since Javascript or Ruby users would expect it to remember the insertion order.
This feature should be set either hardcoded or as an optional feature (but i think no one will really complain if its hardcoded, so it might be for the best)
The only drawback of the hardcoded approach is that it might be sightly less space efficient, I think.
I've defined non-strict comparison operator '=%':
opp.add("==", 9); opp.add("!=", 9); opp.add("=%", 9);
But it won't match 'ANY_OP' pattern, so this do not work:
opMap.add({ARR, ANY_OP, ANY_TYPE}, &ArrayOnAnyOperation);
And I have to define it explicitly:
opMap.add({ARR, ANY_OP, ANY_TYPE}, &ArrayOnAnyOperation);
opMap.add({ARR, "=%", ANY_TYPE}, &ArrayOnAnyOperation);
Hi!
What is the best way to perform hex numbers calculations? Like 0x123 + 0x456.
Hi , it's me again ^^.
I'm currently working on some features (the end goal is to write a little scripting language for a module in our software). I have to pass a pointer of a class to the parser, so i followed your example and stored the pointer as an integer :
parser_data["project"] = reinterpret_cast<int64_t>(_project.data());
std::cout << calculator::calculate("wa = Accessor(project)", parser_data) << "\n";
where Accessor is my constructor for my class and _project is a shared pointer of my project type, but i get an error when trying to read back the integer from the map and the exception token is not a number is thrown :
auto project = reinterpret_cast<datamanager::FPDProject*>(scope["fpdProject"].asInt());
it seemed like a good idea but it doesn't work.
With opMap:
OppMap_t& opp = calculator::Default().opPrecedence;
opp.add("[]", 2); opp.add("()", 2); opp.add(".", 2);
opp.add("**", 3);
opp.add("*", 5); opp.add("/", 5); opp.add("%", 5);
opp.add("+", 6); opp.add("-", 6);
opp.add("<<", 7); opp.add(">>", 7);
opp.add("<", 8); opp.add("<=", 8); opp.add(">=", 8); opp.add(">", 8);
opp.add("==", 9); opp.add("!=", 9); opp.add("=%", 9);
opp.add("&&", 13);
opp.add("||", 14);
opp.add("=", 15); opp.add(":", 15);
opp.add(",", 16);
Parsing expression 'function() == [1,2,3]' - ok, but 'function()==[1,2,3]' gives 'Invalid operator: ==[' exception.
Currently the packToken::str()
function when printing a Map or a List will try to recursively print the entire tree of values. If one these values forms a cycle this recursion will go on until the stack overflows.
We should set a recursion limit for this function.
Hi folks,
I forked the project and added the support for adding variables by references to a TokenMap instance, in addition to the existing extension by values. Example :
double alpha(0.0);
vars["gain"] = std::reference_wrapper(alpha);
The variables get updated upon assignment in a calculation and there is no need to consider the output stream. Let me know if you think it would be worth a contribution.
Thanks.
Jean-Pierre
Hello, I want to use experssion like "!connected". Is there a way to do this? Thank you.
Hello @bamos, with the multi-type support I am presenting on my pull request we will have the option to work with:
etc.
What if we try to mimic python operations and syntax.
Until now we were following C standarts, so true
is the same as 1
and false
the same as 0
,
there were no boolean type, and no string operations.
Do you think it would be a good idea to borrow syntax from Python? I like it and it is usually easy for the user to understand what is happening.
This changes would imply in:
^
to **
true
reserved word would change to True
, and the same for false
+
And some other stuff.
What do you think? Is this a good a idea? May I proceed?
int main() {
TokenMap vars;
vars["pi"] = 3.14;
std::cout << calculator::calculate("-pi+1", &vars) << std::endl;
// Or if you want to evaluate an expression
// several times efficiently:
calculator c1("pi-b");
vars["b"] = 0.14;
std::cout << c1.eval(vars) << std::endl; // 3
vars["b"] = 2.14;
std::cout << c1.eval(vars) << std::endl; // 1
**vars["b"] = {0.1, 0.2};
std::cout << c1.eval(vars) << std::endl;**
return 0;
}
Currently all numeral operations can only return tokens of the REAL type.
It would be expected that if both operands are of type INT that the resulting token would also be of type INT, as it is in most modern languages.
It should install the headers into $PREFIX/include, etc.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.