first finished implementation of Quantity parser

This commit is contained in:
jriegel 2013-09-22 18:03:28 +02:00
parent 4db2355159
commit 3ee7b20927
13 changed files with 1988 additions and 1184 deletions

View File

@ -1,2 +1,2 @@
C:\Tools\GnuWin32\bin\flex.exe -oQuantityLexer.c QuantityParser.l
C:\Tools\GnuWin32\bin\bison -oQuantityParser.c QuantityParser.y
C:\cygwin\bin\flex.exe -oQuantityLexer.c QuantityParser.l
C:\cygwin\bin\bison -oQuantityParser.c QuantityParser.y

2
src/Base/Parser.sh Normal file
View File

@ -0,0 +1,2 @@
flex -oQuantityLexer.c QuantityParser.l
bison -oQuantityParser.c QuantityParser.y

View File

@ -127,6 +127,7 @@ void Quantity_yyerror(char *errorinfo)
namespace QuantityParser {
#define YYINITDEPTH 20
// show the parser the lexer method
#define yylex QuantityLexer
int QuantityLexer(void);

View File

@ -55,6 +55,9 @@ public:
static Quantity parse(const char* buffer);
const Unit & getUnit(void) const{return _Unit;}
double getValue(void) const{return _Value;}
protected:
double _Value;
Unit _Unit;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -32,54 +32,78 @@ ID [a-z][a-z0-9]*
[-+()=/*^] { return *yytext; }
"mm" yylval = 1.0; return UNIT; // millimeter (internal standard length)
"m" yylval = 1000.0; return UNIT; // meter
"cm" yylval = 10.0; return UNIT; // centimeter
"dm" yylval = 100.0; return UNIT; // decimeter
"km" yylval = 1000000.0; return UNIT; // kilometer
"nm" yylval = Quantity(1.0e-6 ,Unit(1)); return UNIT; // nano meter
"ym" yylval = Quantity(1.0e-3 ,Unit(1)); return UNIT; // micro meter
"mm" yylval = Quantity(1.0 ,Unit(1)); return UNIT; // milli meter
"cm" yylval = Quantity(10.0 ,Unit(1)); return UNIT; // centi meter
"dm" yylval = Quantity(100.0 ,Unit(1)); return UNIT; // deci meter
"m" yylval = Quantity(1.0e3 ,Unit(1)); return UNIT; // meter
"km" yylval = Quantity(1.0e6 ,Unit(1)); return UNIT; // kilo meter
"l" yylval = Quantity(1000000.0 ,Unit(3)); return UNIT; // Liter dm^3
"in" yylval = 25.4; return UNIT; // inch
"\"" yylval = 25.4; return UNIT; // inch
"fo" yylval = 304.8; return UNIT; // foot
"'" yylval = 304.8; return UNIT; // foot
"th" yylval = 0.0254; return UNIT; // thou
"yr" yylval = 914.4; return UNIT; // yard
"yg" yylval = Quantity(1.0e-9 ,Unit(0,1)); return UNIT; // milli gram
"mg" yylval = Quantity(1.0e-6 ,Unit(0,1)); return UNIT; // milli gram
"g" yylval = Quantity(1.0e-3 ,Unit(0,1)); return UNIT; // gram
"kg" yylval = Quantity(1.0 ,Unit(0,1)); return UNIT; // kilo gram
"t" yylval = Quantity(1000.0 ,Unit(0,1)); return UNIT; // ton
"kg" yylval = 1.0; return UNIT; // kilogram (internal standard mass)
"g" yylval = 0.001; return UNIT; // gram
"mg" yylval = 0.000001; return UNIT; // milligram
"t" yylval = 1000.0; return UNIT; // ton
"s" yylval = Quantity(1.0 ,Unit(0,0,1)); return UNIT; // second (internal standard time)
"min" yylval = Quantity(60.0 ,Unit(0,0,1)); return UNIT; // minute
"h" yylval = Quantity(3600.0 ,Unit(0,0,1)); return UNIT; // hour
"lb" yylval = 0.45359237; return UNIT; // pound
"oz" yylval = 0.45359237; return UNIT; // ounce
"st" yylval = 6.35029318; return UNIT; // Stone
"cwt" yylval = 50.80234544;return UNIT; // hundredweights
"A" yylval = Quantity(1.0 ,Unit(0,0,0,1)); return UNIT; // Ampere (internal standard electric current)
"mA" yylval = Quantity(0.001 ,Unit(0,0,0,1)); return UNIT; // milli Ampere
"kA" yylval = Quantity(1000.0 ,Unit(0,0,0,1)); return UNIT; // kilo Ampere
"MA" yylval = Quantity(1.0e6 ,Unit(0,0,0,1)); return UNIT; // Mega Ampere
"deg" yylval = 1.0; return UNIT; // degree (internal standard angle)
"rad" yylval = 180/M_PI; return UNIT; // radian
"gon" yylval = 360.0/400.0;return UNIT; // gon
"K" yylval = Quantity(1.0 ,Unit(0,0,0,0,1)); return UNIT; // Kelvin (internal standard thermodynamic temperature)
"mK" yylval = Quantity(0.001 ,Unit(0,0,0,0,1)); return UNIT; // Kelvin
"yK" yylval = Quantity(0.000001 ,Unit(0,0,0,0,1)); return UNIT; // Kelvin
"s" yylval = 1.0; return UNIT; // second (internal standard time)
"min" yylval = 60.0; return UNIT; // minute
"h" yylval = 3600.0; return UNIT; // hour
"mol" yylval = Quantity(1.0 ,Unit(0,0,0,0,0,1)); return UNIT; // Mole (internal standard amount of substance)
"A" yylval = 1.0; return UNIT; // Ampere (internal standard electric current)
"K" yylval = 1.0; return UNIT; // Kelvin (internal standard thermodynamic temperature)
"cd" yylval = 1.0; return UNIT; // Candela (internal standard luminous intensity)
"mol" yylval = 1.0; return UNIT; // Mole (internal standard amount of substance)
"cd" yylval = Quantity(1.0 ,Unit(0,0,0,0,0,0,1)); return UNIT; // Candela (internal standard luminous intensity)
"yl" yylval = 1.0; return UNIT; // microliter mm^3(derived standard volume)
"ml" yylval = 1000.0; return UNIT; // milliliter cm^3
"l" yylval = 1000000.0; return UNIT; // Liter dm^3
"deg" yylval = Quantity(1.0 ,Unit(0,0,0,0,0,0,0,1)); return UNIT; // degree (internal standard angle)
"rad" yylval = Quantity(180/M_PI ,Unit(0,0,0,0,0,0,0,1)); return UNIT; // radian
"gon" yylval = Quantity(360.0/400.0 ,Unit(0,0,0,0,0,0,0,1)); return UNIT; // gon
"in" yylval = Quantity(25.4 ,Unit(1)); return UNIT; // inch
"\"" yylval = Quantity(25.4 ,Unit(1)); return UNIT; // inch
"fo" yylval = Quantity(304.8 ,Unit(1)); return UNIT; // foot
"'" yylval = Quantity(304.8 ,Unit(1)); return UNIT; // foot
"th" yylval = Quantity(0.0254 ,Unit(1)); return UNIT; // thou
"yr" yylval = Quantity(914.4 ,Unit(1)); return UNIT; // yard
"lb" yylval = Quantity(0.45359237 ,Unit(0,1)); return UNIT; // pound
"oz" yylval = Quantity(0.45359237 ,Unit(0,1)); return UNIT; // ounce
"st" yylval = Quantity(6.35029318 ,Unit(0,1)); return UNIT; // Stone
"cwt" yylval = Quantity(50.80234544 ,Unit(0,1)); return UNIT; // hundredweights
{DIGIT}+"."{DIGIT}* {yylval = atof( yytext ); return NUM;}
{DIGIT}+ {yylval = atof( yytext ); return NUM;}
{DIGIT}+["."","]{DIGIT}*[eE][-+]?[0-9]+ {for(char* c=yytext;*c!='\0';c++)if(*c==',')*c='.'; yylval = atof( yytext ); return NUM;}
{DIGIT}+["."","]{DIGIT}* {for(char* c=yytext;*c!='\0';c++)if(*c==',')*c='.'; yylval = atof( yytext ); return NUM;}
{DIGIT}+ {yylval = atof( yytext ); return NUM;}
"pi" {yylval = M_PI ; return NUM;} // constant pi
"e" {yylval = M_E ; return NUM;} // constant e
"acos" return ACOS;
"asin" return ASIN;
"atan" return ATAN;
"atan2" return ATAN2;
"cos" return COS;
"exp" return EXP;
"abs" return ABS;
"mod" return MOD;
"log" return LOG;
"log10" return LOG10;
"pow" return POW;
"sin" return SIN;
"sinh" return SINH;
"tan" return TAN;
"tanh" return TANH;
"sqrt" return SQRT;

View File

@ -11,6 +11,7 @@
/* Bison declarations. */
%token UNIT NUM
%token ACOS ASIN ATAN ATAN2 COS EXP ABS MOD LOG LOG10 POW SIN SINH TAN TANH SQRT;
%left '-' '+'
%left '*' '/'
%left NEG /* negation--unary minus */
@ -22,19 +23,43 @@
%%
input: exp { QuantResult = $1 ; }
;
exp: NUM { $$ = $1; }
| UNIT { $$ = $1; }
| NUM UNIT { $$ = $1*$2; }
| exp '+' exp { $$ = $1 + $3; }
| exp '-' exp { $$ = $1 - $3; }
| exp '*' exp { $$ = $1 * $3; }
| exp '/' exp { $$ = $1 / $3; }
| '-' exp %prec NEG { $$ = -$2; }
| exp '^' NUM { $$ = $1.pow($3); }
| '(' exp ')' { $$ = $2; }
input: num { QuantResult = $1 ; }
| unit { QuantResult = $1 ; }
| quantity { QuantResult = $1 ; }
| quantity quantity { QuantResult = $1 + $2; }
;
num: NUM { $$ = $1; }
| num '+' num { $$ = $1.getValue() + $3.getValue(); }
| num '-' num { $$ = $1.getValue() - $3.getValue(); }
| num '*' num { $$ = $1.getValue() * $3.getValue(); }
| num '/' num { $$ = $1.getValue() / $3.getValue(); }
| '-' num %prec NEG { $$ = -$2.getValue(); }
| num '^' num { $$ = pow ($1.getValue(), $3.getValue());}
| '(' num ')' { $$ = $2; }
| ACOS '(' num ')' { $$ = acos($3.getValue()); }
| ASIN '(' num ')' { $$ = asin($3.getValue()); }
| ATAN '(' num ')' { $$ = atan($3.getValue()); }
| ATAN2 '(' num ',' num ')' { $$ = atan2($3.getValue(),$5.getValue());}
| ABS '(' num ')' { $$ = fabs($3.getValue()); }
| EXP '(' num ')' { $$ = exp($3.getValue()); }
| MOD '(' num ',' num ')' { $$ = fmod($3.getValue(),$5.getValue()); }
| LOG '(' num ')' { $$ = log($3.getValue()); }
| LOG10 '(' num ')' { $$ = log10($3.getValue()); }
| POW '(' num ',' num ')' { $$ = pow($3.getValue(),$5.getValue()); }
| SIN '(' num ')' { $$ = sin($3.getValue()); }
| SINH '(' num ')' { $$ = sinh($3.getValue()); }
| TAN '(' num ')' { $$ = tan($3.getValue()); }
| TANH '(' num ')' { $$ = tanh($3.getValue()); }
| SQRT '(' num ')' { $$ = tanh($3.getValue()); }
| COS '(' num ')' { $$ = cos($3.getValue()); }
;
unit: UNIT { $$ = $1; }
| unit '*' unit { $$ = $1 * $3; }
| unit '/' unit { $$ = $1 / $3; }
| unit '^' num { $$ = $1.pow ($3); }
;
quantity: num unit { $$ = $1*$2; }
;

View File

@ -13,7 +13,11 @@ using namespace Base;
// returns a string which represents the object e.g. when printed in python
std::string QuantityPy::representation(void) const
{
return std::string("<Quantity object>");
std::stringstream ret;
ret << getQuantityPtr()->getValue() << " ";
ret << getQuantityPtr()->getUnit().getString();
return ret.str();
}
PyObject *QuantityPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper

View File

@ -51,7 +51,14 @@ Unit::Unit(int8_t Length,
Unit::Unit()
{
Sig.Length = 0;
Sig.Mass = 0;
Sig.Time = 0;
Sig.ElectricCurrent = 0;
Sig.ThermodynamicTemperature = 0;
Sig.AmountOfSubstance = 0;
Sig.LuminoseIntensity = 0;
Sig.Angle = 0;
}
Unit::Unit(const Unit& that)
@ -148,4 +155,125 @@ Unit& Unit::operator = (const Unit &New)
Sig.Angle = New.Sig.Angle ;
return *this;
}
std::string Unit::getString(void) const
{
std::stringstream ret;
if(isEmpty())
return "";
if( Sig.Length > 0 ||
Sig.Mass > 0 ||
Sig.Time > 0 ||
Sig.ElectricCurrent > 0 ||
Sig.ThermodynamicTemperature> 0 ||
Sig.AmountOfSubstance > 0 ||
Sig.LuminoseIntensity > 0 ||
Sig.Angle > 0 ){
if(Sig.Length > 0){
ret << "mm";
if(Sig.Length >1)
ret << "^" << Sig.Length;
}
if(Sig.Mass > 0){
ret << "kg";
if(Sig.Mass >1)
ret << "^" << Sig.Mass;
}
if(Sig.Time > 0){
ret << "s";
if(Sig.Time >1)
ret << "^" << Sig.Time;
}
if(Sig.ElectricCurrent > 0){
ret << "A";
if(Sig.ElectricCurrent >1)
ret << "^" << Sig.ElectricCurrent;
}
if(Sig.ThermodynamicTemperature > 0){
ret << "K";
if(Sig.ThermodynamicTemperature >1)
ret << "^" << Sig.ThermodynamicTemperature;
}
if(Sig.AmountOfSubstance > 0){
ret << "mol";
if(Sig.AmountOfSubstance >1)
ret << "^" << Sig.AmountOfSubstance;
}
if(Sig.LuminoseIntensity > 0){
ret << "cd";
if(Sig.LuminoseIntensity >1)
ret << "^" << Sig.LuminoseIntensity;
}
if(Sig.Angle > 0){
ret << "deg";
if(Sig.Angle >1)
ret << "^" << Sig.Angle;
}
}else{
ret << "1";
}
if( Sig.Length < 0 ||
Sig.Mass < 0 ||
Sig.Time < 0 ||
Sig.ElectricCurrent < 0 ||
Sig.ThermodynamicTemperature< 0 ||
Sig.AmountOfSubstance < 0 ||
Sig.LuminoseIntensity < 0 ||
Sig.Angle < 0 ){
ret << "/";
if(Sig.Length < 0){
ret << "mm";
if(Sig.Length <-1)
ret << "^" << abs(Sig.Length);
}
if(Sig.Mass < 0){
ret << "kg";
if(Sig.Mass <-1)
ret << "^" << abs(Sig.Mass);
}
if(Sig.Time < 0){
ret << "s";
if(Sig.Time <-1)
ret << "^" << abs(Sig.Time);
}
if(Sig.ElectricCurrent < 0){
ret << "A";
if(Sig.ElectricCurrent <-1)
ret << "^" << abs(Sig.ElectricCurrent);
}
if(Sig.ThermodynamicTemperature < 0){
ret << "K";
if(Sig.ThermodynamicTemperature <-1)
ret << "^" << abs(Sig.ThermodynamicTemperature);
}
if(Sig.AmountOfSubstance < 0){
ret << "mol";
if(Sig.AmountOfSubstance <-1)
ret << "^" << abs(Sig.AmountOfSubstance);
}
if(Sig.LuminoseIntensity < 0){
ret << "cd";
if(Sig.LuminoseIntensity <-1)
ret << "^" << abs(Sig.LuminoseIntensity);
}
if(Sig.Angle < 0){
ret << "deg";
if(Sig.Angle <-1)
ret << "^" << abs(Sig.Angle);
}
}
return ret.str();
}

View File

@ -73,6 +73,7 @@ public:
bool isEmpty(void)const;
char getLengthDimension(void){return Sig.Length;}
std::string getString(void) const;
protected:
UnitSignature Sig;

View File

@ -132,6 +132,7 @@ protected:
protected: // the python API wrapper methodes
static PyObject *sTranslateUnit (PyObject *self,PyObject *args,PyObject *kwd);
static PyObject *sGetWithPrefs (PyObject *self,PyObject *args,PyObject *kwd);
static PyObject *sParseQuantity (PyObject *self,PyObject *args,PyObject *kwd);
};
} // namespace Base

View File

@ -31,6 +31,8 @@
#include "Exception.h"
/// Here the FreeCAD includes sorted by Base,App,Gui......
#include "UnitsApi.h"
#include "Quantity.h"
#include "QuantityPy.h"
@ -66,6 +68,9 @@ PyMethodDef UnitsApi::Methods[] = {
" Temperature \n"
},
{"parseQuantity", (PyCFunction) UnitsApi::sParseQuantity ,1,
"parseQuantity(string) -> Base.Quantity()\n\n"
},
{NULL, NULL, 0, NULL} /* Sentinel */
};
@ -116,3 +121,25 @@ PyObject* UnitsApi::sGetWithPrefs(PyObject * /*self*/, PyObject *args,PyObject *
}
}
PyObject* UnitsApi::sParseQuantity(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/)
{
char *pstr;
if (!PyArg_ParseTuple(args, "s", &pstr)) // convert args: Python->C
return NULL; // NULL triggers exception
Quantity rtn;
try {
rtn = Quantity::parse(pstr);
}
catch (const Base::Exception&) {
PyErr_Format(PyExc_IOError, "invalid unit expression \n");
return 0L;
}
catch (const std::exception&) {
PyErr_Format(PyExc_IOError, "invalid unit expression \n");
return 0L;
}
return new QuantityPy(new Quantity(rtn));
}