summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--RELEASE_NOTES6
-rw-r--r--doc/TODO.txt12
-rw-r--r--src/func.cc46
-rw-r--r--src/lexer.l98
4 files changed, 133 insertions, 29 deletions
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index 51b20ee..69fe747 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -1,8 +1,10 @@
-OpenSCAD 2010.06
+OpenSCAD 2010.XX
================
-... add stuff here ...
+o Added rands() function
+o Added sign() function
+o Bugfixes: More robust DXF export
OpenSCAD 2010.05
================
diff --git a/doc/TODO.txt b/doc/TODO.txt
index 7348bec..6d608ee 100644
--- a/doc/TODO.txt
+++ b/doc/TODO.txt
@@ -131,10 +131,11 @@ o Function-Module-Interface
- Pass a module instanciation to a function (e.g. for a volume() function)
- Pass a function to a module instanciation (e.g. for dynamic extrusion paths)
o Language Frontend
+ - include statement doesn't support nesting. This can be fixed by
+ keeping a nested stack of current input files in the lexer. See
+ the "Flex & Bison" O'Reilly book, "Start States and Nested Input
+ Files", page 28, for an example.
- Allow local variables and functions everywhere (not only on module level)
- - Add "use" statement to load modules. Like include but read a module only once,
- ignore all top level objects (they are used as module testcase) and search in
- a module search path.
- allow 0/1 f/t FALSE/TRUE as boolean values
- allow any expression to be evaluated as boolean (e.g. 1 = true, 0 = false)
- Rethink for vs. intersection_for vs. group. Should for loops
@@ -194,6 +195,11 @@ o Consider evaluating all referenced files relative to the document path instead
of being absolute. This would e.g. make regression testing of dumpcaching easier.
This would require us to pass a document contect to all traversal methods though.
+BUILD SYSTEM
+------------
+o Fedora is reported to ship with byacc, which doesn't support bison extensions (e.g. %debuig). Look into this, either be yacc-compatible or force the build system to use bison.
+o We currently link in -lboost_thread. Should we always use -lboost_thread-mt under Linux or can we pick this up using qmake?
+
TESTING
-------
o Caching and MDI looks suspicious when the code relies on external resources
diff --git a/src/func.cc b/src/func.cc
index d73b152..7627a94 100644
--- a/src/func.cc
+++ b/src/func.cc
@@ -125,6 +125,51 @@ Value builtin_sign(const Context *, const QVector<QString>&, const QVector<Value
return Value();
}
+double frand()
+{
+ return rand()/(double(RAND_MAX)+1);
+}
+
+double frand(double min, double max)
+{
+ return (min>max) ? frand()*(min-max)+max : frand()*(max-min)+min;
+}
+
+Value builtin_rands(const Context *, const QVector<QString>&, const QVector<Value> &args)
+{
+ if (args.size() == 3 &&
+ args[0].type == Value::NUMBER &&
+ args[1].type == Value::NUMBER &&
+ args[2].type == Value::NUMBER)
+ {
+ srand((unsigned int)time(0));
+ }
+ else if (args.size() == 4 &&
+ args[0].type == Value::NUMBER &&
+ args[1].type == Value::NUMBER &&
+ args[2].type == Value::NUMBER &&
+ args[3].type == Value::NUMBER)
+ {
+ srand((unsigned int)args[3].num);
+ }
+ else
+ {
+ return Value();
+ }
+
+ Value v;
+ v.type = Value::VECTOR;
+
+ for (int i=0; i<args[2].num; i++)
+ {
+ Value * r = new Value(frand(args[0].num, args[1].num));
+ v.vec.append(r);
+ }
+
+ return v;
+}
+
+
Value builtin_min(const Context *, const QVector<QString>&, const QVector<Value> &args)
{
if (args.size() >= 1 && args[0].type == Value::NUMBER) {
@@ -298,6 +343,7 @@ void initialize_builtin_functions()
{
builtin_functions["abs"] = new BuiltinFunction(&builtin_abs);
builtin_functions["sign"] = new BuiltinFunction(&builtin_sign);
+ builtin_functions["rands"] = new BuiltinFunction(&builtin_rands);
builtin_functions["min"] = new BuiltinFunction(&builtin_min);
builtin_functions["max"] = new BuiltinFunction(&builtin_max);
builtin_functions["sin"] = new BuiltinFunction(&builtin_sin);
diff --git a/src/lexer.l b/src/lexer.l
index 48729c8..9e8aaf8 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -28,9 +28,10 @@
#include "openscad.h"
#include "printutils.h"
#include "parser_yacc.h"
+#include <QStack>
#include <QFileInfo>
#include <QDir>
-
+QString* stringcontents;
int lexerget_lineno(void);
#ifdef __GNUC__
static void yyunput(int, char*) __attribute__((unused));
@@ -58,33 +59,33 @@ extern const char *parser_source_path;
} \
}
+void includefile();
+QDir sourcepath();
+QStack<QDir> path_stack;
+
+QString filename;
+QString filepath;
+
%}
%option yylineno
%option noyywrap
-%x comment
+%x comment string
+%x include
+
+DIGIT [0-9]
%%
-include[ \t\r\n>]*"<"[^ \t\r\n>]+">" {
- QString filename(yytext);
- filename.remove(QRegExp("^include[ \t\r\n>]*<"));
- filename.remove(QRegExp(">$"));
- QFileInfo finfo(QDir(parser_source_path), filename);
- if (!finfo.exists()) {
- finfo = QFileInfo(QDir(librarydir), filename);
- }
- handle_dep(finfo.absoluteFilePath());
- yyin = fopen(finfo.absoluteFilePath().toLocal8Bit(), "r");
- if (!yyin) {
- PRINTA("WARNING: Can't open input file `%1'.", filename);
- } else {
- yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
- BEGIN(INITIAL);
- }
+include[ \t\r\n>]*"<" { BEGIN(include); }
+<include>{
+[^\t\r\n>]+"/" { filepath = yytext; }
+[^\t\r\n>/]+ { filename = yytext; }
+">" { BEGIN(INITIAL); includefile(); }
}
+
use[ \t\r\n>]*"<"[^ \t\r\n>]+">" {
QString filename(yytext);
filename.remove(QRegExp("^use[ \t\r\n>]*<"));
@@ -106,7 +107,7 @@ use[ \t\r\n>]*"<"[^ \t\r\n>]+">" {
finfo = QFileInfo(QDir(librarydir), filename);
}
- PRINTF("WARNING: Support for implicit include will be removed in future releases. Use `include <filename>' instead.");
+ PRINTF("DEPRECATED: Support for implicit include will be removed in future releases. Use `include <filename>' instead.");
handle_dep(finfo.absoluteFilePath());
yyin = fopen(finfo.absoluteFilePath().toLocal8Bit(), "r");
if (!yyin) {
@@ -119,6 +120,8 @@ use[ \t\r\n>]*"<"[^ \t\r\n>]+">" {
}
<<EOF>> {
+ if(!path_stack.isEmpty())
+ path_stack.pop();
if (yyin && yyin != stdin)
fclose(yyin);
yypop_buffer_state();
@@ -135,13 +138,21 @@ use[ \t\r\n>]*"<"[^ \t\r\n>]+">" {
"false" return TOK_FALSE;
"undef" return TOK_UNDEF;
-[0-9][0-9.]* { parserlval.number = QString(yytext).toDouble(); return TOK_NUMBER; }
+{DIGIT}+|{DIGIT}*\.{DIGIT}+|{DIGIT}+\.{DIGIT}* { parserlval.number = QString(yytext).toDouble(); return TOK_NUMBER; }
"$"?[a-zA-Z0-9_]+ { parserlval.text = strdup(yytext); return TOK_ID; }
-\"[^"]*\" {
- parserlval.text = strdup(yytext+1);
- parserlval.text[strlen(parserlval.text)-1] = 0;
- return TOK_STRING;
+\" { BEGIN(string); stringcontents = new QString(); }
+<string>{
+\\n { stringcontents->append('\n'); }
+\\t { stringcontents->append('\t'); }
+\\r { stringcontents->append('\r'); }
+\\\\ { stringcontents->append('\\'); }
+\\\" { stringcontents->append('"'); }
+[^\\\n\"]+ { stringcontents->append(lexertext); }
+\" { BEGIN(INITIAL);
+ parserlval.text = strdup(stringcontents->toLocal8Bit());
+ delete stringcontents;
+ return TOK_STRING; }
}
[\n\r\t ]
@@ -159,3 +170,42 @@ use[ \t\r\n>]*"<"[^ \t\r\n>]+">" {
. { return yytext[0]; }
+%%
+
+QDir sourcepath()
+{
+ if(!path_stack.isEmpty())
+ return path_stack.top();
+
+ return QDir(parser_source_path);
+}
+
+void includefile()
+{
+ if(filename.isEmpty())
+ return;
+
+ if(filepath.isEmpty()) {
+ path_stack.push(sourcepath());
+ } else {
+ QFileInfo dirinfo(sourcepath(),filepath);
+ path_stack.push(dirinfo.dir());
+ filepath.clear();
+ }
+
+ QFileInfo finfo(sourcepath(), filename);
+ if (!finfo.exists()) {
+ finfo = QFileInfo(QDir(librarydir), filename);
+ }
+
+ handle_dep(finfo.absoluteFilePath());
+ yyin = fopen(finfo.absoluteFilePath().toLocal8Bit(), "r");
+ if (!yyin) {
+ PRINTA("WARNING: Can't open input file `%1'.", filename);
+ return;
+ }
+ filename.clear();
+
+ yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
+}
+
contact: Jan Huwald // Impressum