diff options
author | clifford <clifford@b57f626f-c46c-0410-a088-ec61d464b74c> | 2009-07-01 08:06:06 (GMT) |
---|---|---|
committer | clifford <clifford@b57f626f-c46c-0410-a088-ec61d464b74c> | 2009-07-01 08:06:06 (GMT) |
commit | 27ecd0b1d0bf0114b465beeb4db482f0f1f87c52 (patch) | |
tree | fbf5c869321f15b75b6f5c1c2299b5f5fd960e18 | |
parent | b7ca4bfdb38b8caf153f6d93b1d3959f8ffd53ca (diff) |
Clifford Wolf:
Another cleanup in expression handling
git-svn-id: http://svn.clifford.at/openscad/trunk@43 b57f626f-c46c-0410-a088-ec61d464b74c
-rw-r--r-- | expr.cc | 197 | ||||
-rw-r--r-- | lexer.l | 27 | ||||
-rw-r--r-- | openscad.h | 21 | ||||
-rw-r--r-- | parser.y | 105 | ||||
-rw-r--r-- | value.cc | 78 |
5 files changed, 294 insertions, 134 deletions
@@ -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(); + 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]; } - case 'I': + return Value(); + } + if (type == "I") return children[0]->evaluate(context).inv(); - case 'C': + if (type == "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(); + 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; } - 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 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); - case 'N': - { - Value v = children[0]->evaluate(context); + 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::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); + 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(); + 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(); } @@ -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]; } @@ -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(); @@ -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; @@ -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) { |