mirror of https://github.com/vitalif/openscad
merged current master
commit
00c237d3ce
|
@ -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
|
||||
================
|
||||
|
|
12
doc/TODO.txt
12
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
|
||||
|
|
46
src/func.cc
46
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);
|
||||
|
|
98
src/lexer.l
98
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 ));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue