summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--context.cc66
-rw-r--r--expr.cc65
-rw-r--r--func.cc123
-rw-r--r--module.cc71
-rw-r--r--openscad.cc18
-rw-r--r--openscad.h162
-rw-r--r--openscad.pro2
-rw-r--r--value.cc90
8 files changed, 595 insertions, 2 deletions
diff --git a/context.cc b/context.cc
new file mode 100644
index 0000000..6cfae25
--- /dev/null
+++ b/context.cc
@@ -0,0 +1,66 @@
+/*
+ * OpenSCAD (www.openscad.at)
+ * Copyright (C) 2009 Clifford Wolf <clifford@clifford.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "openscad.h"
+
+void Context::args(const QVector<QString> &argnames, const QVector<Expression*> &argexpr,
+ const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues)
+{
+ for (int i=0; i<argnames.size(); i++) {
+ variables[argnames[i]] = argexpr[i] ? argexpr[i]->evaluate(this->parent) : Value();
+ }
+
+ int posarg = 0;
+ for (int i=0; i<call_argnames.size(); i++) {
+ if (call_argnames[i].isEmpty()) {
+ variables[argnames[posarg++]] = call_argvalues[i];
+ } else {
+ variables[call_argnames[i]] = call_argvalues[i];
+ }
+ }
+}
+
+Value Context::lookup_variable(QString name)
+{
+ if (variables.contains(name))
+ return variables[name];
+ if (parent)
+ return parent->lookup_variable(name);
+ return Value();
+}
+
+Value Context::evaluate_function(QString name, const QVector<QString> &argnames, const QVector<Value> &argvalues)
+{
+ if (functions_p->contains(name))
+ return functions_p->value(name)->evaluate(this, argnames, argvalues);
+ if (parent)
+ return parent->evaluate_function(name, argnames, argvalues);
+ return Value();
+}
+
+AbstractNode *Context::evaluate_module(QString name, const QVector<QString> &argnames, const QVector<Value> &argvalues)
+{
+ if (modules_p->contains(name))
+ return modules_p->value(name)->evaluate(this, argnames, argvalues);
+ if (parent)
+ return parent->evaluate_module(name, argnames, argvalues);
+ return NULL;
+}
+
diff --git a/expr.cc b/expr.cc
new file mode 100644
index 0000000..ddc0135
--- /dev/null
+++ b/expr.cc
@@ -0,0 +1,65 @@
+/*
+ * OpenSCAD (www.openscad.at)
+ * Copyright (C) 2009 Clifford Wolf <clifford@clifford.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "openscad.h"
+
+Expression::Expression()
+{
+ type = 0;
+}
+
+Expression::~Expression()
+{
+ for (int i=0; i < children.size(); i++)
+ delete children[i];
+}
+
+Value Expression::evaluate(Context *context)
+{
+ switch (type)
+ {
+ case '*':
+ return children[0]->evaluate(context) * children[1]->evaluate(context);
+ case '/':
+ return children[0]->evaluate(context) / children[1]->evaluate(context);
+ case '%':
+ return children[0]->evaluate(context) % children[1]->evaluate(context);
+ case '+':
+ return children[0]->evaluate(context) + children[1]->evaluate(context);
+ case '-':
+ return children[0]->evaluate(context) - children[1]->evaluate(context);
+ case 'I':
+ return children[0]->evaluate(context).inv();
+ case 'C':
+ return const_value;
+ case 'V':
+ return context->lookup_variable(var_name);
+ 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:
+ return Value();
+ }
+}
+
diff --git a/func.cc b/func.cc
new file mode 100644
index 0000000..db8dea9
--- /dev/null
+++ b/func.cc
@@ -0,0 +1,123 @@
+/*
+ * OpenSCAD (www.openscad.at)
+ * Copyright (C) 2009 Clifford Wolf <clifford@clifford.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "openscad.h"
+#include <math.h>
+
+AbstractFunction::~AbstractFunction()
+{
+}
+
+Value AbstractFunction::evaluate(Context*, const QVector<QString>&, const QVector<Value>&)
+{
+ return Value();
+}
+
+Function::~Function()
+{
+ for (int i=0; i < argexpr.size(); i++)
+ delete argexpr[i];
+}
+
+Value Function::evaluate(Context *ctx, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues)
+{
+ Context c(ctx);
+ c.args(argnames, argexpr, call_argnames, call_argvalues);
+ return expr.evaluate(&c);
+}
+
+QHash<QString, AbstractFunction*> builtin_functions;
+
+BuiltinFunction::~BuiltinFunction()
+{
+}
+
+Value BuiltinFunction::evaluate(Context*, const QVector<QString>&, const QVector<Value> &call_argvalues)
+{
+ return eval_func(call_argvalues);
+}
+
+Value builtin_sin(const QVector<Value> &args)
+{
+ if (args[0].is_nan || args[0].is_vector)
+ return Value();
+ return Value(sin(args[0].x));
+}
+
+Value builtin_cos(const QVector<Value> &args)
+{
+ if (args[0].is_nan || args[0].is_vector)
+ return Value();
+ return Value(cos(args[0].x));
+}
+
+Value builtin_asin(const QVector<Value> &args)
+{
+ if (args[0].is_nan || args[0].is_vector)
+ return Value();
+ return Value(asin(args[0].x));
+}
+
+Value builtin_acos(const QVector<Value> &args)
+{
+ if (args[0].is_nan || args[0].is_vector)
+ return Value();
+ return Value(acos(args[0].x));
+}
+
+Value builtin_tan(const QVector<Value> &args)
+{
+ if (args[0].is_nan || args[0].is_vector)
+ return Value();
+ return Value(tan(args[0].x));
+}
+
+Value builtin_atan(const QVector<Value> &args)
+{
+ if (args[0].is_nan || args[0].is_vector)
+ return Value();
+ return Value(atan(args[0].x));
+}
+
+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));
+}
+
+void initialize_builtin_functions()
+{
+ builtin_functions["sin"] = new BuiltinFunction(&builtin_sin);
+ builtin_functions["cos"] = new BuiltinFunction(&builtin_cos);
+ builtin_functions["asin"] = new BuiltinFunction(&builtin_asin);
+ builtin_functions["acos"] = new BuiltinFunction(&builtin_acos);
+ builtin_functions["tan"] = new BuiltinFunction(&builtin_tan);
+ builtin_functions["atan"] = new BuiltinFunction(&builtin_atan);
+ builtin_functions["atan2"] = new BuiltinFunction(&builtin_atan2);
+}
+
+void destroy_builtin_functions()
+{
+ foreach (AbstractFunction *v, builtin_functions)
+ delete v;
+ builtin_functions.clear();
+}
+
diff --git a/module.cc b/module.cc
new file mode 100644
index 0000000..0393d07
--- /dev/null
+++ b/module.cc
@@ -0,0 +1,71 @@
+/*
+ * OpenSCAD (www.openscad.at)
+ * Copyright (C) 2009 Clifford Wolf <clifford@clifford.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "openscad.h"
+
+AbstractModule::~AbstractModule()
+{
+}
+
+AbstractNode *AbstractModule::evaluate(Context*, const QVector<QString>&, const QVector<Value>&)
+{
+ return NULL;
+}
+
+ModuleInstanciation::~ModuleInstanciation()
+{
+ foreach (Expression *v, argexpr)
+ delete v;
+}
+
+Module::~Module()
+{
+ foreach (Expression *v, assignments)
+ delete v;
+ foreach (AbstractFunction *v, functions)
+ delete v;
+ foreach (AbstractModule *v, modules)
+ delete v;
+}
+
+AbstractNode *Module::evaluate(Context *ctx, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues)
+{
+ Context c(ctx);
+ c.args(argnames, argexpr, call_argnames, call_argvalues);
+
+ /* FIXME */
+
+ return NULL;
+}
+
+QHash<QString, AbstractModule*> builtin_modules;
+
+void initialize_builtin_modules()
+{
+ /* FIXME */
+}
+
+void destroy_builtin_modules()
+{
+ foreach (AbstractModule *v, builtin_modules)
+ delete v;
+ builtin_modules.clear();
+}
+
diff --git a/openscad.cc b/openscad.cc
index f312285..f824c32 100644
--- a/openscad.cc
+++ b/openscad.cc
@@ -18,12 +18,28 @@
*
*/
+#include "openscad.h"
+
extern int parserdebug;
int parserparse(void);
int main()
{
+ int rc = 0;
+
+ initialize_builtin_functions();
+ initialize_builtin_modules();
+
+ Context ctx(NULL);
+ ctx.functions_p = &builtin_functions;
+ ctx.modules_p = &builtin_modules;
+
// parserdebug = 1;
- return parserparse();
+ rc = parserparse();
+
+ destroy_builtin_functions();
+ destroy_builtin_modules();
+
+ return rc;
}
diff --git a/openscad.h b/openscad.h
index 08c5f96..944c8ce 100644
--- a/openscad.h
+++ b/openscad.h
@@ -21,5 +21,167 @@
#ifndef OPENSCAD_H
#define OPENSCAD_H
+#include <QHash>
+#include <QVector>
+
+class Value;
+class Expression;
+
+class AbstractFunction;
+class BuiltinFunction;
+class Function;
+
+class AbstractModule;
+class ModuleInstanciation;
+class Module;
+
+class Context;
+class AbstractNode;
+
+class Value
+{
+public:
+ double x, y, z;
+ bool is_vector;
+ bool is_nan;
+
+ Value() : x(0), y(0), z(0), is_vector(false), is_nan(true) { }
+ Value(double v1) : x(v1), y(0), z(0), is_vector(false), is_nan(false) { }
+ Value(double v1, double v2, double v3) : x(v1), y(v2), z(v3), is_vector(true), is_nan(false) { }
+ Value(const Value &v) : x(v.x), y(v.y), z(v.z), is_vector(v.is_vector), is_nan(v.is_nan) { }
+
+ Value& operator = (const Value &v);
+ 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;
+};
+
+class Expression
+{
+public:
+ QVector<Expression*> children;
+
+ Value const_value;
+ QString var_name;
+
+ QString call_funcname;
+ QVector<QString> call_argnames;
+
+ // Math operators: * / % + -
+ // Invert (prefix '-'): I
+ // Constant value: C
+ // Variable: V
+ // Function call: F
+ char type;
+
+ Expression();
+ ~Expression();
+
+ Value evaluate(Context *context);
+};
+
+class AbstractFunction
+{
+public:
+ virtual ~AbstractFunction();
+ virtual Value evaluate(Context *ctx, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues);
+};
+
+class BuiltinFunction : public AbstractFunction
+{
+public:
+ typedef Value (*eval_func_t)(const QVector<Value> &args);
+ eval_func_t eval_func;
+
+ BuiltinFunction(eval_func_t f) : eval_func(f) { }
+ virtual ~BuiltinFunction();
+
+ virtual Value evaluate(Context *ctx, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues);
+};
+
+class Function : public AbstractFunction
+{
+public:
+ QVector<QString> argnames;
+ QVector<Expression*> argexpr;
+
+ Expression expr;
+
+ Function() { }
+ virtual ~Function();
+
+ virtual Value evaluate(Context *ctx, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues);
+};
+
+extern QHash<QString, AbstractFunction*> builtin_functions;
+extern void initialize_builtin_functions();
+extern void destroy_builtin_functions();
+
+class AbstractModule
+{
+public:
+ virtual ~AbstractModule();
+ virtual AbstractNode *evaluate(Context *ctx, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues);
+};
+
+class ModuleInstanciation
+{
+public:
+ QString label;
+ QString modname;
+ QVector<QString> argnames;
+ QVector<Expression*> argexpr;
+
+ ModuleInstanciation() { }
+ ~ModuleInstanciation();
+};
+
+class Module : public AbstractModule
+{
+public:
+ QVector<QString> argnames;
+ QVector<Expression*> argexpr;
+
+ QHash<QString, Expression*> assignments;
+ QHash<QString, AbstractFunction*> functions;
+ QHash<QString, AbstractModule*> modules;
+
+ QVector<ModuleInstanciation> children;
+
+ Module() { }
+ virtual ~Module();
+
+ virtual AbstractNode *evaluate(Context *ctx, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues);
+};
+
+extern QHash<QString, AbstractModule*> builtin_modules;
+extern void initialize_builtin_modules();
+extern void destroy_builtin_modules();
+
+class Context
+{
+public:
+ Context *parent;
+ QHash<QString, Value> variables;
+ QHash<QString, AbstractFunction*> *functions_p;
+ QHash<QString, AbstractModule*> *modules_p;
+
+ Context(Context *parent) : parent(parent) { }
+ void args(const QVector<QString> &argnames, const QVector<Expression*> &argexpr, const QVector<QString> &call_argnames, const QVector<Value> &call_argvalues);
+
+ Value lookup_variable(QString name);
+ Value evaluate_function(QString name, const QVector<QString> &argnames, const QVector<Value> &argvalues);
+ AbstractNode *evaluate_module(QString name, const QVector<QString> &argnames, const QVector<Value> &argvalues);
+};
+
+class AbstractNode
+{
+public:
+ QVector<AbstractNode*> children;
+};
+
#endif
diff --git a/openscad.pro b/openscad.pro
index 73d4e86..e914eeb 100644
--- a/openscad.pro
+++ b/openscad.pro
@@ -6,5 +6,5 @@ LEXSOURCES = lexer.l
YACCSOURCES = parser.y
HEADERS = openscad.h
-SOURCES = openscad.cc
+SOURCES = openscad.cc value.cc expr.cc func.cc module.cc context.cc
diff --git a/value.cc b/value.cc
new file mode 100644
index 0000000..d6af1a3
--- /dev/null
+++ b/value.cc
@@ -0,0 +1,90 @@
+/*
+ * OpenSCAD (www.openscad.at)
+ * Copyright (C) 2009 Clifford Wolf <clifford@clifford.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "openscad.h"
+#include <math.h>
+
+Value& Value::operator = (const Value &v) {
+ x = v.x;
+ y = v.y;
+ z = v.z;
+ is_vector = v.is_vector;
+ is_nan = v.is_nan;
+ return *this;
+}
+
+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);
+ 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);
+ return Value();
+}
+
+Value Value::operator * (const Value &v) const {
+ if (is_nan || v.is_nan)
+ return Value();
+ if (is_vector && v.is_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 (v.is_vector) {
+ return Value(x * v.x, x * v.y, x * v.z);
+ }
+ return Value(x * v.x);
+}
+
+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);
+}
+
+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));
+}
+
+Value Value::inv() const {
+ if (is_nan)
+ return Value();
+ if (is_vector)
+ return Value(-x, -y, -z);
+ return Value(-x);
+}
+
contact: Jan Huwald // Impressum