diff options
-rw-r--r-- | csg.cc | 3 | ||||
-rw-r--r-- | example.scad | 4 | ||||
-rw-r--r-- | expr.cc | 89 | ||||
-rw-r--r-- | func.cc | 42 | ||||
-rw-r--r-- | lexer.l | 16 | ||||
-rw-r--r-- | module.cc | 10 | ||||
-rw-r--r-- | openscad.h | 46 | ||||
-rw-r--r-- | parser.y | 87 | ||||
-rw-r--r-- | primitive.cc | 43 | ||||
-rw-r--r-- | trans.cc | 2 | ||||
-rw-r--r-- | value.cc | 223 |
11 files changed, 419 insertions, 146 deletions
@@ -47,6 +47,9 @@ public: AbstractNode *CsgModule::evaluate(const Context*, const QVector<QString>&, const QVector<Value>&, const QVector<AbstractNode*> child_nodes) const { + if (child_nodes.size() == 1) + return child_nodes[0]; + CsgNode *node = new CsgNode(type); foreach (AbstractNode *v, child_nodes) node->children.append(v); diff --git a/example.scad b/example.scad index a2b86c1..9f21ea7 100644 --- a/example.scad +++ b/example.scad @@ -24,8 +24,8 @@ module test001() module test002() { difference() { - cube([2 2 0.5], 1); - cube([0.5 0.5 2], 1); + cube([2 2 0.5], true); + cube([0.5 0.5 2], true); } } @@ -45,25 +45,79 @@ Value Expression::evaluate(const Context *context) const return children[0]->evaluate(context) + children[1]->evaluate(context); case '-': 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.r_begin = v1.num; + r.r_step = v2.num; + r.r_end = v3.num; + return r; + } + return Value(); + } case 'V': - return Value(children[0]->evaluate(context), children[1]->evaluate(context), children[2]->evaluate(context)); + { + 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) + return Value(v1.num, v2.num, v3.num); + return Value(); + } + case 'M': + { + double m[16]; + for (int i=0; i<16; i++) { + Value v = children[i]->evaluate(context); + if (v.type != Value::NUMBER) + return Value(); + m[i] = v.num; + } + return Value(m); + } case 'L': return context->lookup_variable(var_name); - case 'M': + case 'N': { Value v = children[0]->evaluate(context); - if (v.is_nan || !v.is_vector) - return Value(); - if (var_name == QString("x")) + + if (v.type == Value::VECTOR && var_name == QString("x")) return Value(v.x); - if (var_name == QString("y")) + if (v.type == Value::VECTOR && var_name == QString("y")) return Value(v.y); - if (var_name == QString("z")) + if (v.type == Value::VECTOR && var_name == QString("z")) return Value(v.z); + + if (v.type == Value::RANGE && var_name == QString("begin")) + return Value(v.r_begin); + if (v.type == Value::RANGE && var_name == QString("step")) + return Value(v.r_step); + if (v.type == Value::RANGE && var_name == QString("end")) + return Value(v.r_end); + + for (int i=0; i<16; i++) { + QString n; + n.sprintf("m%d", i+1); + if (v.type == Value::MATRIX && var_name == n) + return Value(v.m[i]); + } + return Value(); } case 'F': @@ -87,16 +141,33 @@ QString Expression::dump() const case '%': case '+': case '-': - return QString("(%1%2%3)").arg(children[0]->dump(), QString(type), children[1]->dump()); + return QString("(%1 %2 %3)").arg(children[0]->dump(), QString(type), children[1]->dump()); + case '?': + return QString("(%1 ? %2 : %3)").arg(children[0]->dump(), children[1]->dump(), children[2]->dump()); case 'I': return QString("(-%1)").arg(children[0]->dump()); case 'C': return const_value.dump(); + case 'R': + return QString("[%1 : %2 : %3]").arg(children[0]->dump(), children[1]->dump(), children[2]->dump()); case 'V': return QString("[%1, %2, %3]").arg(children[0]->dump(), children[1]->dump(), children[2]->dump()); + case 'M': + { + QString text = "["; + for (int i = 0; i < 16; i++) { + if (i % 4 == 0 && i > 0) + text += ";"; + if (i > 0) + text += " "; + text += children[i]->dump(); + } + text += "]"; + return text; + } case 'L': return var_name; - case 'M': + case 'N': return QString("(%1.%2)").arg(children[0]->dump(), var_name); case 'F': { @@ -82,51 +82,51 @@ QString BuiltinFunction::dump(QString indent, QString name) const Value builtin_sin(const QVector<Value> &args) { - if (args[0].is_nan || args[0].is_vector) - return Value(); - return Value(sin(args[0].x)); + if (args[0].type == Value::NUMBER) + Value(sin(args[0].num)); + return Value(); } Value builtin_cos(const QVector<Value> &args) { - if (args[0].is_nan || args[0].is_vector) - return Value(); - return Value(cos(args[0].x)); + if (args[0].type == Value::NUMBER) + Value(cos(args[0].num)); + return Value(); } Value builtin_asin(const QVector<Value> &args) { - if (args[0].is_nan || args[0].is_vector) - return Value(); - return Value(asin(args[0].x)); + if (args[0].type == Value::NUMBER) + Value(asin(args[0].num)); + return Value(); } Value builtin_acos(const QVector<Value> &args) { - if (args[0].is_nan || args[0].is_vector) - return Value(); - return Value(acos(args[0].x)); + if (args[0].type == Value::NUMBER) + Value(acos(args[0].num)); + return Value(); } Value builtin_tan(const QVector<Value> &args) { - if (args[0].is_nan || args[0].is_vector) - return Value(); - return Value(tan(args[0].x)); + if (args[0].type == Value::NUMBER) + Value(tan(args[0].num)); + return Value(); } Value builtin_atan(const QVector<Value> &args) { - if (args[0].is_nan || args[0].is_vector) - return Value(); - return Value(atan(args[0].x)); + if (args[0].type == Value::NUMBER) + Value(atan(args[0].num)); + return Value(); } Value builtin_atan2(const QVector<Value> &args) { - if (args[0].is_nan || args[0].is_vector || args[1].is_nan || args[1].is_vector) - return Value(); - return Value(atan2(args[0].x, args[1].x)); + if (args[0].type == Value::NUMBER && args[1].type == Value::NUMBER) + Value(atan2(args[0].num, args[1].num)); + return Value(); } void initialize_builtin_functions() @@ -32,10 +32,15 @@ int lexerget_lineno(void); %x comment -WS [\n\r\t ] - %% +"module" return TOK_MODULE; +"function" return TOK_FUNCTION; + +"true" return TOK_TRUE; +"false" return TOK_FALSE; +"undef" return TOK_UNDEF; + [0-9][0-9.]* { parserlval.number = atof(yytext); return TOK_NUMBER; } [a-zA-Z0-9_]+ { parserlval.text = strdup(yytext); return TOK_ID; } \"[^"]*\" { parserlval.text = strdup(yytext); return TOK_STRING; } @@ -43,6 +48,7 @@ WS [\n\r\t ] "." return '.'; "," return ','; ";" return ';'; +"?" return '?'; ":" return ':'; "=" return '='; "*" return '*'; @@ -57,15 +63,11 @@ WS [\n\r\t ] "[" return '['; "]" return ']'; -"module"/{WS} return TOK_MODULE; -"function"/{WS} return TOK_FUNCTION; - +[\n\r\t ] \/\/[^\n]*\n "/*" BEGIN(comment); <comment>"*/" BEGIN(INITIAL); <comment>.|\n -{WS}* - . { fprintf(stderr, "Unrecognized input character in line %d: %s\n", lexerget_lineno(), yytext); exit(1); } @@ -28,6 +28,9 @@ AbstractModule::~AbstractModule() AbstractNode *AbstractModule::evaluate(const Context*, const QVector<QString>&, const QVector<Value>&, const QVector<AbstractNode*> child_nodes) const { + if (child_nodes.size() == 1) + return child_nodes[0]; + AbstractNode *node = new AbstractNode(); foreach (AbstractNode *v, child_nodes) node->children.append(v); @@ -120,6 +123,13 @@ AbstractNode *Module::evaluate(const Context *ctx, const QVector<QString> &call_ foreach (AbstractNode *v, child_nodes) node->children.append(v); + if (node->children.size() == 1) { + AbstractNode *c = node->children[0]; + node->children.clear(); + delete node; + return c; + } + return node; } @@ -47,21 +47,37 @@ class AbstractNode; class Value { public: + enum type_e { + UNDEFINED, + BOOL, + NUMBER, + RANGE, + VECTOR, + MATRIX, + STRING + }; + + enum type_e type; + + bool b; + double num; double x, y, z; + double r_begin; + double r_step; + double r_end; + double m[16]; QString text; - bool is_vector; - bool is_range; - bool is_string; - bool is_nan; - - Value() : x(0), y(0), z(0), is_vector(false), is_range(false), is_string(false), is_nan(true) { } - Value(const QString &t) : x(0), y(0), z(0), text(t), is_vector(false), is_range(false), is_string(true), is_nan(true) { } - Value(double v1) : x(v1), y(0), z(0), is_vector(false), is_range(false), is_string(false), is_nan(false) { } - Value(double v1, double v2, double v3) : x(v1), y(v2), z(v3), is_vector(true), is_range(false), is_string(false), is_nan(false) { } - Value(const Value &v) : x(v.x), y(v.y), z(v.z), text(v.text), is_vector(v.is_vector), is_range(v.is_range), is_string(v.is_string), is_nan(v.is_nan) { } - Value(const Value &v1, const Value &v2, const Value &v3); + Value(); + Value(bool v); + Value(double v); + Value(double v1, double v2, double v3); + Value(double m[16]); + Value(const QString &t); + + Value(const Value &v); Value& operator = (const Value &v); + Value operator + (const Value &v) const; Value operator - (const Value &v) const; Value operator * (const Value &v) const; @@ -70,6 +86,9 @@ public: Value inv() const; QString dump() const; + +private: + void reset_undef(); }; class Expression @@ -84,11 +103,14 @@ public: QVector<QString> call_argnames; // Math operators: * / % + - + // Condition (?: operator): ? // Invert (prefix '-'): I // Constant value: C + // Create Range: R // Create Vector: V + // Create Matrix: M // Lookup Variable: L - // Lookup Member: M + // Lookup member per name: N // Function call: F char type; @@ -56,10 +56,15 @@ public: %token TOK_MODULE %token TOK_FUNCTION + %token <text> TOK_ID %token <text> TOK_STRING %token <number> TOK_NUMBER +%token TOK_TRUE +%token TOK_FALSE +%token TOK_UNDEF + %left '+' '-' %left '*' '/' '%' %left '.' @@ -163,6 +168,21 @@ single_module_instantciation: } ; expr: + TOK_TRUE { + $$ = new Expression(); + $$->type = 'C'; + $$->const_value = Value(true); + } | + TOK_FALSE { + $$ = new Expression(); + $$->type = 'C'; + $$->const_value = Value(false); + } | + TOK_UNDEF { + $$ = new Expression(); + $$->type = 'C'; + $$->const_value = Value(); + } | TOK_ID { $$ = new Expression(); $$->type = 'L'; @@ -171,7 +191,7 @@ expr: } | expr '.' TOK_ID { $$ = new Expression(); - $$->type = 'M'; + $$->type = 'N'; $$->children.append($1); $$->var_name = QString($3); free($3); @@ -187,23 +207,42 @@ expr: $$->type = 'C'; $$->const_value = Value($1); } | - TOK_NUMBER ':' TOK_NUMBER { + '[' expr ':' expr ']' { + Expression *e_one = new Expression(); + e_one->type = 'C'; + e_one->const_value = Value(1.0); $$ = new Expression(); - $$->type = 'C'; - $$->const_value = Value($1, 1, $3); - $$->const_value.is_range = true; + $$->type = 'R'; + $$->children.append($2); + $$->children.append(e_one); + $$->children.append($4); } | - TOK_NUMBER ':' TOK_NUMBER ':' TOK_NUMBER { + '[' expr ':' expr ':' expr ']' { $$ = new Expression(); - $$->type = 'C'; - $$->const_value = Value($1, $3, $5); - $$->const_value.is_range = true; + $$->type = 'R'; + $$->children.append($2); + $$->children.append($4); + $$->children.append($6); } | '[' TOK_NUMBER TOK_NUMBER TOK_NUMBER ']' { $$ = new Expression(); $$->type = 'C'; $$->const_value = Value($2, $3, $4); } | + '[' TOK_NUMBER TOK_NUMBER TOK_NUMBER TOK_NUMBER ';' + TOK_NUMBER TOK_NUMBER TOK_NUMBER TOK_NUMBER ';' + TOK_NUMBER TOK_NUMBER TOK_NUMBER TOK_NUMBER ';' + TOK_NUMBER TOK_NUMBER TOK_NUMBER TOK_NUMBER ']' { + $$ = new Expression(); + $$->type = 'C'; + double m[16] = { + $2, $3, $4, $5, + $7, $8, $9, $10, + $12, $13, $14, $15, + $17, $18, $19, $20, + }; + $$->const_value = Value(m); + } | '[' expr ',' expr ',' expr ']' { $$ = new Expression(); $$->type = 'V'; @@ -211,6 +250,29 @@ expr: $$->children.append($4); $$->children.append($6); } | + '[' expr ',' expr ',' expr ',' expr ';' + expr ',' expr ',' expr ',' expr ';' + expr ',' expr ',' expr ',' expr ';' + expr ',' expr ',' expr ',' expr ']' { + $$ = new Expression(); + $$->type = 'M'; + $$->children.append($2); + $$->children.append($4); + $$->children.append($6); + $$->children.append($8); + $$->children.append($10); + $$->children.append($12); + $$->children.append($14); + $$->children.append($16); + $$->children.append($18); + $$->children.append($20); + $$->children.append($22); + $$->children.append($24); + $$->children.append($26); + $$->children.append($28); + $$->children.append($30); + $$->children.append($32); + } | expr '*' expr { $$ = new Expression(); $$->type = '*'; @@ -252,6 +314,13 @@ expr: '(' expr ')' { $$ = $2; } | + expr '?' expr ':' expr { + $$ = new Expression(); + $$->type = '?'; + $$->children.append($1); + $$->children.append($3); + $$->children.append($5); + } | TOK_ID '(' arguments_call ')' { $$ = new Expression(); $$->type = 'F'; diff --git a/primitive.cc b/primitive.cc index 9f5e7f3..91f84d5 100644 --- a/primitive.cc +++ b/primitive.cc @@ -73,24 +73,25 @@ AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const QVector<QStrin if (type == CUBE) { Value size = c.lookup_variable("size"); Value center = c.lookup_variable("center"); - if (size.is_vector) { + if (size.type == Value::VECTOR) { node->x = size.x; node->y = size.y; node->z = size.z; - } else if (!size.is_nan) { - node->x = size.x; - node->y = size.x; - node->z = size.x; } - if (!center.is_vector && !center.is_nan) { - node->center = center.x != 0; + if (size.type == Value::NUMBER) { + node->x = size.num; + node->y = size.num; + node->z = size.num; + } + if (center.type == Value::BOOL) { + node->center = center.b; } } if (type == SPHERE) { Value r = c.lookup_variable("r"); - if (!r.is_vector && !r.is_nan) { - node->r1 = r.x; + if (r.type == Value::NUMBER) { + node->r1 = r.num; } } @@ -100,21 +101,21 @@ AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const QVector<QStrin Value r1 = c.lookup_variable("r1"); Value r2 = c.lookup_variable("r2"); Value center = c.lookup_variable("center"); - if (!h.is_vector && !h.is_nan) { - node->h = h.x; + if (h.type == Value::NUMBER) { + node->h = h.num; } - if (!r.is_vector && !r.is_nan) { - node->r1 = r.x; - node->r2 = r.x; + if (r.type == Value::NUMBER) { + node->r1 = r.num; + node->r2 = r.num; } - if (!r1.is_vector && !r1.is_nan) { - node->r1 = r1.x; + if (r1.type == Value::NUMBER) { + node->r1 = r1.num; } - if (!r2.is_vector && !r2.is_nan) { + if (r2.type == Value::NUMBER) { node->r2 = r2.x; } - if (!center.is_vector && !center.is_nan) { - node->center = center.x != 0; + if (center.type == Value::BOOL) { + node->center = center.b; } } @@ -212,11 +213,11 @@ QString PrimitiveNode::dump(QString indent) const { QString text; if (type == CUBE) - text.sprintf("cube(size = [%f %f %f], center = %d);\n", x, y, z, center ? 1 : 0); + text.sprintf("cube(size = [%f %f %f], center = %s);\n", x, y, z, center ? "true" : "false"); if (type == SPHERE) text.sprintf("sphere(r = %f);\n", r1); if (type == CYLINDER) - text.sprintf("cylinder(h = %f, r1 = %f, r2 = %f, center = %d);\n", h, r1, r2, center ? 1 : 0); + text.sprintf("cylinder(h = %f, r1 = %f, r2 = %f, center = %s);\n", h, r1, r2, center ? "true" : "false"); return indent + text; } @@ -39,7 +39,7 @@ public: AbstractNode *TransModule::evaluate(const Context*, const QVector<QString>&, const QVector<Value> &call_argvalues, const QVector<AbstractNode*> child_nodes) const { TransNode *node = new TransNode(); - if (call_argvalues.size() == 1 && call_argvalues[0].is_vector) { + if (call_argvalues.size() == 1 && call_argvalues[0].type == Value::VECTOR) { node->x = call_argvalues[0].x; node->y = call_argvalues[0].y; node->z = call_argvalues[0].z; @@ -20,121 +20,216 @@ #include "openscad.h" -Value::Value(const Value &v1, const Value &v2, const Value &v3) -{ - if (v1.is_nan || v1.is_vector) - goto create_nan; - if (v2.is_nan || v2.is_vector) - goto create_nan; - if (v3.is_nan || v3.is_vector) - goto create_nan; - - x = v1.x; - y = v2.x; - z = v3.x; - - is_vector = true; - is_range = false; - is_string = false; - is_nan = false; - return; - -create_nan: - x = 0; - y = 0; - z = 0; +Value::Value() +{ + reset_undef(); +} + +Value::Value(bool v) +{ + reset_undef(); + type = BOOL; + b = v; +} + +Value::Value(double v) +{ + reset_undef(); + type = NUMBER; + num = v; +} + +Value::Value(double v1, double v2, double v3) +{ + reset_undef(); + type = VECTOR; + x = v1; + y = v2; + z = v3; +} - is_vector = false; - is_range = false; - is_string = false; - is_nan = true; +Value::Value(double m[16]) +{ + reset_undef(); + type = MATRIX; + for (int i=0; i<16; i++) + this->m[i] = m[i]; +} + +Value::Value(const QString &t) +{ + reset_undef(); + type = STRING; + text = t; +} + +Value::Value(const Value &v) +{ + reset_undef(); + type = v.type; + b = v.b; + num = v.num; + x = v.x; + y = v.y; + z = v.z; + for (int i=0; i<16; i++) + m[i] = v.m[i]; + text = v.text; } Value& Value::operator = (const Value &v) { + reset_undef(); + type = v.type; + b = v.b; + num = v.num; x = v.x; y = v.y; z = v.z; - is_vector = v.is_vector; - is_nan = v.is_nan; + for (int i=0; i<16; i++) + m[i] = v.m[i]; + text = v.text; return *this; } Value Value::operator + (const Value &v) const { - if (is_nan || v.is_nan) - return Value(); - if (is_vector && v.is_vector) + if (type == VECTOR && v.type == VECTOR) { return Value(x + v.x, y + v.y, z + v.z); - if (!is_vector && !v.is_vector) - return Value(x + v.x); + } + if (type == MATRIX && v.type == MATRIX) { + double m_[16]; + for (int i=0; i<16; i++) + m_[i] = m[i] + v.m[i]; + return Value(m); + } + if (type == NUMBER && v.type == NUMBER) { + return Value(num + v.num); + } return Value(); } Value Value::operator - (const Value &v) const { - if (is_nan || v.is_nan) - return Value(); - if (is_vector && v.is_vector) - return Value(x - v.x, y - v.y, z - v.z); - if (!is_vector && !v.is_vector) - return Value(x - v.x); + if (type == VECTOR && v.type == VECTOR) { + return Value(x + v.x, y + v.y, z + v.z); + } + if (type == MATRIX && v.type == MATRIX) { + double m_[16]; + for (int i=0; i<16; i++) + m_[i] = m[i] + v.m[i]; + return Value(m); + } + if (type == NUMBER && v.type == NUMBER) { + return Value(num + v.num); + } return Value(); } Value Value::operator * (const Value &v) const { - if (is_nan || v.is_nan) - return Value(); - if (is_vector && v.is_vector) { + if (type == VECTOR && v.type == VECTOR) { double nx = (y-v.y)*(z-v.z) - (z-v.z)*(y-v.y); double ny = (z-v.z)*(x-v.x) - (x-v.x)*(z-v.z); double nz = (x-v.x)*(y-v.y) - (y-v.y)*(x-v.x); return Value(nx, ny, nz); } - if (is_vector) { - return Value(x * v.x, y * v.x, z * v.x); + if (type == VECTOR && v.type == NUMBER) { + return Value(x * v.num, y * v.num, z * v.num); + } + if (type == NUMBER && v.type == VECTOR) { + return Value(num * v.x, num * v.y, num * v.z); } - if (v.is_vector) { - return Value(x * v.x, x * v.y, x * v.z); + if (type == NUMBER && v.type == NUMBER) { + return Value(num * v.num); } - return Value(x * v.x); + return Value(); } Value Value::operator / (const Value &v) const { - if (is_nan || v.is_nan || is_vector || v.is_vector) - return Value(); - return Value(x / v.x); + if (type == NUMBER && v.type == NUMBER) { + return Value(num / v.num); + } + return Value(); } Value Value::operator % (const Value &v) const { - if (is_nan || v.is_nan || is_vector || v.is_vector) - return Value(); - return Value(fmod(x, v.x)); + if (type == NUMBER && v.type == NUMBER) { + return Value(fmod(num, v.num)); + } + return Value(); } Value Value::inv() const { - if (is_nan) - return Value(); - if (is_vector) + if (type == MATRIX) { + double m_[16]; + for (int i=0; i<16; i++) + m_[i] = -m[i]; + return Value(m); + } + if (type == VECTOR) return Value(-x, -y, -z); - return Value(-x); + if (type == NUMBER) + return Value(-x); + return Value(); } QString Value::dump() const { - if (is_nan) - return QString("NaN"); - if (is_vector) { + if (type == STRING) { + return QString("\"") + text + QString("\""); + } + if (type == MATRIX) { + QString text = "["; + for (int i=0; i<16; i++) { + QString t; + t.sprintf("%f", m[i]); + if (i % 4 == 0 && i > 0) + text += ";"; + if (i > 0) + text += " "; + text += t; + } + text += "]"; + return text; + } + if (type == VECTOR) { QString text; text.sprintf("[%f %f %f]", x, y, z); return text; } - QString text; - text.sprintf("%f", x); - return text; + if (type == RANGE) { + QString text; + text.sprintf("[ %f : %f : %f ]", r_begin, r_step, r_end); + return text; + } + if (type == NUMBER) { + QString text; + text.sprintf("%f", num); + return text; + } + if (type == BOOL) { + return QString(b ? "true" : "false"); + } + return QString("undef"); +} + +void Value::reset_undef() +{ + type = UNDEFINED; + b = false; + num = 0; + r_begin = 0; + r_step = 0; + r_end = 0; + x = 0; + y = 0; + z = 0; + for (int i=0; i<16; i++) + m[i] = 0; + text = QString(); } |