mirror of https://github.com/vitalif/openscad
Clifford Wolf:
Another cleanup in expression handling git-svn-id: http://svn.clifford.at/openscad/trunk@43 b57f626f-c46c-0410-a088-ec61d464b74cstl_dim
parent
b7ca4bfdb3
commit
27ecd0b1d0
213
expr.cc
213
expr.cc
|
@ -22,7 +22,6 @@
|
|||
|
||||
Expression::Expression()
|
||||
{
|
||||
type = 0;
|
||||
const_value = NULL;
|
||||
}
|
||||
|
||||
|
@ -36,124 +35,138 @@ Expression::~Expression()
|
|||
|
||||
Value Expression::evaluate(const Context *context) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case '*':
|
||||
if (type == "!")
|
||||
return ! children[0]->evaluate(context);
|
||||
if (type == "&&")
|
||||
return children[0]->evaluate(context) && children[1]->evaluate(context);
|
||||
if (type == "||")
|
||||
return children[0]->evaluate(context) || children[1]->evaluate(context);
|
||||
if (type == "*")
|
||||
return children[0]->evaluate(context) * children[1]->evaluate(context);
|
||||
case '/':
|
||||
if (type == "/")
|
||||
return children[0]->evaluate(context) / children[1]->evaluate(context);
|
||||
case '%':
|
||||
if (type == "%")
|
||||
return children[0]->evaluate(context) % children[1]->evaluate(context);
|
||||
case '+':
|
||||
if (type == "+")
|
||||
return children[0]->evaluate(context) + children[1]->evaluate(context);
|
||||
case '-':
|
||||
if (type == "-")
|
||||
return children[0]->evaluate(context) - children[1]->evaluate(context);
|
||||
case '?':
|
||||
{
|
||||
Value v = children[0]->evaluate(context);
|
||||
if (v.type == Value::BOOL)
|
||||
return children[v.b ? 1 : 2]->evaluate(context);
|
||||
return Value();
|
||||
}
|
||||
case 'I':
|
||||
return children[0]->evaluate(context).inv();
|
||||
case 'C':
|
||||
return *const_value;
|
||||
case 'R':
|
||||
{
|
||||
Value v1 = children[0]->evaluate(context);
|
||||
Value v2 = children[1]->evaluate(context);
|
||||
Value v3 = children[2]->evaluate(context);
|
||||
if (v1.type == Value::NUMBER && v2.type == Value::NUMBER && v3.type == Value::NUMBER) {
|
||||
Value r = Value();
|
||||
r.type = Value::RANGE;
|
||||
r.range_begin = v1.num;
|
||||
r.range_step = v2.num;
|
||||
r.range_end = v3.num;
|
||||
return r;
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
case 'V':
|
||||
{
|
||||
Value v;
|
||||
v.type = Value::VECTOR;
|
||||
for (int i = 0; i < children.size(); i++)
|
||||
v.vec.append(new Value(children[i]->evaluate(context)));
|
||||
return v;
|
||||
}
|
||||
case 'L':
|
||||
return context->lookup_variable(var_name);
|
||||
case 'N':
|
||||
{
|
||||
Value v = children[0]->evaluate(context);
|
||||
|
||||
if (v.type == Value::VECTOR && var_name == QString("x"))
|
||||
return *v.vec[0];
|
||||
if (v.type == Value::VECTOR && var_name == QString("y"))
|
||||
return *v.vec[1];
|
||||
if (v.type == Value::VECTOR && var_name == QString("z"))
|
||||
return *v.vec[2];
|
||||
|
||||
if (v.type == Value::RANGE && var_name == QString("begin"))
|
||||
return Value(v.range_begin);
|
||||
if (v.type == Value::RANGE && var_name == QString("step"))
|
||||
return Value(v.range_step);
|
||||
if (v.type == Value::RANGE && var_name == QString("end"))
|
||||
return Value(v.range_end);
|
||||
|
||||
return Value();
|
||||
}
|
||||
case 'F':
|
||||
{
|
||||
QVector<Value> argvalues;
|
||||
for (int i=0; i < children.size(); i++)
|
||||
argvalues.append(children[i]->evaluate(context));
|
||||
return context->evaluate_function(call_funcname, call_argnames, argvalues);
|
||||
}
|
||||
default:
|
||||
abort();
|
||||
if (type == "<")
|
||||
return children[0]->evaluate(context) < children[1]->evaluate(context);
|
||||
if (type == "<=")
|
||||
return children[0]->evaluate(context) <= children[1]->evaluate(context);
|
||||
if (type == "==")
|
||||
return children[0]->evaluate(context) == children[1]->evaluate(context);
|
||||
if (type == "!=")
|
||||
return children[0]->evaluate(context) != children[1]->evaluate(context);
|
||||
if (type == ">=")
|
||||
return children[0]->evaluate(context) >= children[1]->evaluate(context);
|
||||
if (type == ">")
|
||||
return children[0]->evaluate(context) > children[1]->evaluate(context);
|
||||
if (type == "?:") {
|
||||
Value v = children[0]->evaluate(context);
|
||||
if (v.type == Value::BOOL)
|
||||
return children[v.b ? 1 : 2]->evaluate(context);
|
||||
return Value();
|
||||
}
|
||||
if (type == "[]") {
|
||||
Value v1 = children[0]->evaluate(context);
|
||||
Value v2 = children[1]->evaluate(context);
|
||||
if (v1.type == Value::VECTOR && v2.type == Value::NUMBER) {
|
||||
int i = v2.num;
|
||||
if (i < v1.vec.size())
|
||||
return *v1.vec[i];
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
if (type == "I")
|
||||
return children[0]->evaluate(context).inv();
|
||||
if (type == "C")
|
||||
return *const_value;
|
||||
if (type == "R") {
|
||||
Value v1 = children[0]->evaluate(context);
|
||||
Value v2 = children[1]->evaluate(context);
|
||||
Value v3 = children[2]->evaluate(context);
|
||||
if (v1.type == Value::NUMBER && v2.type == Value::NUMBER && v3.type == Value::NUMBER) {
|
||||
Value r = Value();
|
||||
r.type = Value::RANGE;
|
||||
r.range_begin = v1.num;
|
||||
r.range_step = v2.num;
|
||||
r.range_end = v3.num;
|
||||
return r;
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
if (type == "V") {
|
||||
Value v;
|
||||
v.type = Value::VECTOR;
|
||||
for (int i = 0; i < children.size(); i++)
|
||||
v.vec.append(new Value(children[i]->evaluate(context)));
|
||||
return v;
|
||||
}
|
||||
if (type == "L")
|
||||
return context->lookup_variable(var_name);
|
||||
if (type == "N")
|
||||
{
|
||||
Value v = children[0]->evaluate(context);
|
||||
|
||||
if (v.type == Value::VECTOR && var_name == QString("x"))
|
||||
return *v.vec[0];
|
||||
if (v.type == Value::VECTOR && var_name == QString("y"))
|
||||
return *v.vec[1];
|
||||
if (v.type == Value::VECTOR && var_name == QString("z"))
|
||||
return *v.vec[2];
|
||||
|
||||
if (v.type == Value::RANGE && var_name == QString("begin"))
|
||||
return Value(v.range_begin);
|
||||
if (v.type == Value::RANGE && var_name == QString("step"))
|
||||
return Value(v.range_step);
|
||||
if (v.type == Value::RANGE && var_name == QString("end"))
|
||||
return Value(v.range_end);
|
||||
|
||||
return Value();
|
||||
}
|
||||
if (type == "F") {
|
||||
QVector<Value> argvalues;
|
||||
for (int i=0; i < children.size(); i++)
|
||||
argvalues.append(children[i]->evaluate(context));
|
||||
return context->evaluate_function(call_funcname, call_argnames, argvalues);
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
QString Expression::dump() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case '*':
|
||||
case '/':
|
||||
case '%':
|
||||
case '+':
|
||||
case '-':
|
||||
if (type == "*" || type == "/" || type == "%" || type == "+" || type == "-" ||
|
||||
type == "<" || type == "<=" || type == "==" || type == "!=" || type == ">=" || type == ">")
|
||||
return QString("(%1 %2 %3)").arg(children[0]->dump(), QString(type), children[1]->dump());
|
||||
case '?':
|
||||
if (type == "?:")
|
||||
return QString("(%1 ? %2 : %3)").arg(children[0]->dump(), children[1]->dump(), children[2]->dump());
|
||||
case 'I':
|
||||
if (type == "[]")
|
||||
return QString("(%1[%2])").arg(children[0]->dump(), children[1]->dump());
|
||||
if (type == "I")
|
||||
return QString("(-%1)").arg(children[0]->dump());
|
||||
case 'C':
|
||||
if (type == "C")
|
||||
return const_value->dump();
|
||||
case 'R':
|
||||
if (type == "R")
|
||||
return QString("[%1 : %2 : %3]").arg(children[0]->dump(), children[1]->dump(), children[2]->dump());
|
||||
case 'V':
|
||||
if (type == "V")
|
||||
return QString("[%1, %2, %3]").arg(children[0]->dump(), children[1]->dump(), children[2]->dump());
|
||||
case 'L':
|
||||
if (type == "L")
|
||||
return var_name;
|
||||
case 'N':
|
||||
if (type == "N")
|
||||
return QString("(%1.%2)").arg(children[0]->dump(), var_name);
|
||||
case 'F':
|
||||
{
|
||||
QString text = call_funcname + QString("(");
|
||||
for (int i=0; i < children.size(); i++) {
|
||||
if (i > 0)
|
||||
text += QString(", ");
|
||||
if (!call_argnames[i].isEmpty())
|
||||
text += call_argnames[i] + QString(" = ");
|
||||
text += children[i]->dump();
|
||||
}
|
||||
return text + QString(")");
|
||||
if (type == "F") {
|
||||
QString text = call_funcname + QString("(");
|
||||
for (int i=0; i < children.size(); i++) {
|
||||
if (i > 0)
|
||||
text += QString(", ");
|
||||
if (!call_argnames[i].isEmpty())
|
||||
text += call_argnames[i] + QString(" = ");
|
||||
text += children[i]->dump();
|
||||
}
|
||||
default:
|
||||
abort();
|
||||
return text + QString(")");
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
|
|
27
lexer.l
27
lexer.l
|
@ -55,29 +55,18 @@ extern const char *parser_input_buffer;
|
|||
"$"?[a-zA-Z0-9_]+ { parserlval.text = strdup(yytext); return TOK_ID; }
|
||||
\"[^"]*\" { parserlval.text = strdup(yytext); return TOK_STRING; }
|
||||
|
||||
"." return '.';
|
||||
"," return ',';
|
||||
";" return ';';
|
||||
"?" return '?';
|
||||
":" return ':';
|
||||
"=" return '=';
|
||||
"*" return '*';
|
||||
"/" return '/';
|
||||
"%" return '%';
|
||||
"+" return '+';
|
||||
"-" return '-';
|
||||
"(" return '(';
|
||||
")" return ')';
|
||||
"{" return '{';
|
||||
"}" return '}';
|
||||
"[" return '[';
|
||||
"]" return ']';
|
||||
|
||||
[\n\r\t ]
|
||||
\/\/[^\n]*\n
|
||||
"/*" BEGIN(comment);
|
||||
<comment>"*/" BEGIN(INITIAL);
|
||||
<comment>.|\n
|
||||
|
||||
. { fprintf(stderr, "Unrecognized input character in line %d: %s\n", lexerget_lineno(), yytext); exit(1); }
|
||||
"<=" return LE;
|
||||
">=" return GE;
|
||||
"==" return EQ;
|
||||
"!=" return NE;
|
||||
"&&" return AND;
|
||||
"||" return OR;
|
||||
|
||||
. { return yytext[0]; }
|
||||
|
||||
|
|
21
openscad.h
21
openscad.h
|
@ -104,11 +104,23 @@ public:
|
|||
Value(const Value &v);
|
||||
Value& operator = (const Value &v);
|
||||
|
||||
Value operator ! () const;
|
||||
Value operator && (const Value &v) const;
|
||||
Value operator || (const Value &v) const;
|
||||
|
||||
Value operator + (const Value &v) const;
|
||||
Value operator - (const Value &v) const;
|
||||
Value operator * (const Value &v) const;
|
||||
Value operator / (const Value &v) const;
|
||||
Value operator % (const Value &v) const;
|
||||
|
||||
Value operator < (const Value &v) const;
|
||||
Value operator <= (const Value &v) const;
|
||||
Value operator == (const Value &v) const;
|
||||
Value operator != (const Value &v) const;
|
||||
Value operator >= (const Value &v) const;
|
||||
Value operator > (const Value &v) const;
|
||||
|
||||
Value inv() const;
|
||||
|
||||
bool getnum(double &v) const;
|
||||
|
@ -131,8 +143,11 @@ public:
|
|||
QString call_funcname;
|
||||
QVector<QString> call_argnames;
|
||||
|
||||
// Math operators: * / % + -
|
||||
// Condition (?: operator): ?
|
||||
// Boolean: ! && ||
|
||||
// Operators: * / % + -
|
||||
// Relations: < <= == != >= >
|
||||
// Vector element: []
|
||||
// Condition operator: ?:
|
||||
// Invert (prefix '-'): I
|
||||
// Constant value: C
|
||||
// Create Range: R
|
||||
|
@ -141,7 +156,7 @@ public:
|
|||
// Lookup Variable: L
|
||||
// Lookup member per name: N
|
||||
// Function call: F
|
||||
char type;
|
||||
QString type;
|
||||
|
||||
Expression();
|
||||
~Expression();
|
||||
|
|
105
parser.y
105
parser.y
|
@ -66,9 +66,15 @@ public:
|
|||
%token TOK_FALSE
|
||||
%token TOK_UNDEF
|
||||
|
||||
%token LE GE EQ NE AND OR
|
||||
|
||||
%left '+' '-'
|
||||
%left '*' '/' '%'
|
||||
%left '.'
|
||||
%left '<' LE GE '>'
|
||||
%left EQ NE
|
||||
%left AND
|
||||
%left OR
|
||||
|
||||
%type <expr> expr
|
||||
%type <value> vector_const
|
||||
|
@ -173,69 +179,69 @@ single_module_instantciation:
|
|||
expr:
|
||||
TOK_TRUE {
|
||||
$$ = new Expression();
|
||||
$$->type = 'C';
|
||||
$$->type = "C";
|
||||
$$->const_value = new Value(true);
|
||||
} |
|
||||
TOK_FALSE {
|
||||
$$ = new Expression();
|
||||
$$->type = 'C';
|
||||
$$->type = "C";
|
||||
$$->const_value = new Value(false);
|
||||
} |
|
||||
TOK_UNDEF {
|
||||
$$ = new Expression();
|
||||
$$->type = 'C';
|
||||
$$->type = "C";
|
||||
$$->const_value = new Value();
|
||||
} |
|
||||
TOK_ID {
|
||||
$$ = new Expression();
|
||||
$$->type = 'L';
|
||||
$$->type = "L";
|
||||
$$->var_name = QString($1);
|
||||
free($1);
|
||||
} |
|
||||
expr '.' TOK_ID {
|
||||
$$ = new Expression();
|
||||
$$->type = 'N';
|
||||
$$->type = "N";
|
||||
$$->children.append($1);
|
||||
$$->var_name = QString($3);
|
||||
free($3);
|
||||
} |
|
||||
TOK_STRING {
|
||||
$$ = new Expression();
|
||||
$$->type = 'C';
|
||||
$$->type = "C";
|
||||
$$->const_value = new Value(QString($1));
|
||||
free($1);
|
||||
} |
|
||||
TOK_NUMBER {
|
||||
$$ = new Expression();
|
||||
$$->type = 'C';
|
||||
$$->type = "C";
|
||||
$$->const_value = new Value($1);
|
||||
} |
|
||||
'[' expr ':' expr ']' {
|
||||
Expression *e_one = new Expression();
|
||||
e_one->type = 'C';
|
||||
e_one->type = "C";
|
||||
e_one->const_value = new Value(1.0);
|
||||
$$ = new Expression();
|
||||
$$->type = 'R';
|
||||
$$->type = "R";
|
||||
$$->children.append($2);
|
||||
$$->children.append(e_one);
|
||||
$$->children.append($4);
|
||||
} |
|
||||
'[' expr ':' expr ':' expr ']' {
|
||||
$$ = new Expression();
|
||||
$$->type = 'R';
|
||||
$$->type = "R";
|
||||
$$->children.append($2);
|
||||
$$->children.append($4);
|
||||
$$->children.append($6);
|
||||
} |
|
||||
'[' ']' {
|
||||
$$ = new Expression();
|
||||
$$->type = 'C';
|
||||
$$->type = "C";
|
||||
$$->const_value = new Value();
|
||||
$$->const_value->type = Value::VECTOR;
|
||||
} |
|
||||
'[' vector_const ']' {
|
||||
$$ = new Expression();
|
||||
$$->type = 'C';
|
||||
$$->type = "C";
|
||||
$$->const_value = $2;
|
||||
} |
|
||||
'[' vector_expr ']' {
|
||||
|
@ -243,31 +249,79 @@ expr:
|
|||
} |
|
||||
expr '*' expr {
|
||||
$$ = new Expression();
|
||||
$$->type = '*';
|
||||
$$->type = "*";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
expr '/' expr {
|
||||
$$ = new Expression();
|
||||
$$->type = '/';
|
||||
$$->type = "/";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
expr '%' expr {
|
||||
$$ = new Expression();
|
||||
$$->type = '%';
|
||||
$$->type = "%";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
expr '+' expr {
|
||||
$$ = new Expression();
|
||||
$$->type = '+';
|
||||
$$->type = "+";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
expr '-' expr {
|
||||
$$ = new Expression();
|
||||
$$->type = '-';
|
||||
$$->type = "-";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
expr '<' expr {
|
||||
$$ = new Expression();
|
||||
$$->type = "<";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
expr LE expr {
|
||||
$$ = new Expression();
|
||||
$$->type = "<=";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
expr EQ expr {
|
||||
$$ = new Expression();
|
||||
$$->type = "==";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
expr NE expr {
|
||||
$$ = new Expression();
|
||||
$$->type = "!=";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
expr GE expr {
|
||||
$$ = new Expression();
|
||||
$$->type = ">=";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
expr '>' expr {
|
||||
$$ = new Expression();
|
||||
$$->type = "<";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
expr AND expr {
|
||||
$$ = new Expression();
|
||||
$$->type = "&&";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
expr OR expr {
|
||||
$$ = new Expression();
|
||||
$$->type = "||";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
|
@ -276,7 +330,12 @@ expr:
|
|||
} |
|
||||
'-' expr {
|
||||
$$ = new Expression();
|
||||
$$->type = 'I';
|
||||
$$->type = "I";
|
||||
$$->children.append($2);
|
||||
} |
|
||||
'!' expr {
|
||||
$$ = new Expression();
|
||||
$$->type = "!";
|
||||
$$->children.append($2);
|
||||
} |
|
||||
'(' expr ')' {
|
||||
|
@ -284,14 +343,20 @@ expr:
|
|||
} |
|
||||
expr '?' expr ':' expr {
|
||||
$$ = new Expression();
|
||||
$$->type = '?';
|
||||
$$->type = "?:";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
$$->children.append($5);
|
||||
} |
|
||||
expr '[' expr ']' {
|
||||
$$ = new Expression();
|
||||
$$->type = "[]";
|
||||
$$->children.append($1);
|
||||
$$->children.append($3);
|
||||
} |
|
||||
TOK_ID '(' arguments_call ')' {
|
||||
$$ = new Expression();
|
||||
$$->type = 'F';
|
||||
$$->type = "F";
|
||||
$$->call_funcname = QString($1);
|
||||
$$->call_argnames = $3->argnames;
|
||||
$$->children = $3->argexpr;
|
||||
|
|
78
value.cc
78
value.cc
|
@ -73,6 +73,30 @@ Value& Value::operator = (const Value &v)
|
|||
return *this;
|
||||
}
|
||||
|
||||
Value Value::operator ! () const
|
||||
{
|
||||
if (type == BOOL) {
|
||||
return Value(!b);
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value Value::operator && (const Value &v) const
|
||||
{
|
||||
if (type == BOOL && v.type == BOOL) {
|
||||
return Value(b && v.b);
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value Value::operator || (const Value &v) const
|
||||
{
|
||||
if (type == BOOL && v.type == BOOL) {
|
||||
return Value(b || v.b);
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value Value::operator + (const Value &v) const
|
||||
{
|
||||
if (type == VECTOR && v.type == VECTOR) {
|
||||
|
@ -155,6 +179,60 @@ Value Value::operator % (const Value &v) const
|
|||
return Value();
|
||||
}
|
||||
|
||||
Value Value::operator < (const Value &v) const
|
||||
{
|
||||
if (type == NUMBER && v.type == NUMBER) {
|
||||
return Value(num < v.num);
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value Value::operator <= (const Value &v) const
|
||||
{
|
||||
if (type == NUMBER && v.type == NUMBER) {
|
||||
return Value(num <= v.num);
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value Value::operator == (const Value &v) const
|
||||
{
|
||||
if (type == BOOL && v.type == BOOL) {
|
||||
return Value(b == v.b);
|
||||
}
|
||||
if (type == NUMBER && v.type == NUMBER) {
|
||||
return Value(num == v.num);
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value Value::operator != (const Value &v) const
|
||||
{
|
||||
if (type == BOOL && v.type == BOOL) {
|
||||
return Value(b != v.b);
|
||||
}
|
||||
if (type == NUMBER && v.type == NUMBER) {
|
||||
return Value(num != v.num);
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value Value::operator >= (const Value &v) const
|
||||
{
|
||||
if (type == NUMBER && v.type == NUMBER) {
|
||||
return Value(num >= v.num);
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value Value::operator > (const Value &v) const
|
||||
{
|
||||
if (type == NUMBER && v.type == NUMBER) {
|
||||
return Value(num > v.num);
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value Value::inv() const
|
||||
{
|
||||
if (type == VECTOR) {
|
||||
|
|
Loading…
Reference in New Issue