diff options
| author | Marius Kintel <marius@kintel.net> | 2010-12-09 18:04:11 (GMT) | 
|---|---|---|
| committer | Marius Kintel <marius@kintel.net> | 2010-12-09 18:04:11 (GMT) | 
| commit | 00c237d3ce6af7114a8bd138ef897d7e83178383 (patch) | |
| tree | 4a1d524d73d170dfd10582e915397e7c7234944a | |
| parent | 399d9c0b3fb3df58cb8c0c9e8e218eda481342c9 (diff) | |
| parent | d98e398ec185f87501c1374cc3863457ed450663 (diff) | |
merged current master
| -rw-r--r-- | RELEASE_NOTES | 6 | ||||
| -rw-r--r-- | doc/TODO.txt | 12 | ||||
| -rw-r--r-- | src/func.cc | 46 | ||||
| -rw-r--r-- | src/lexer.l | 98 | 
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 )); +} + | 
