1
2 /*
3 * Math2
4 * Copyright (c) 2004-2006 by Mattias Hultgren <mattias_hultgren@tele2.se>
5 *
6 * See math2.h
7 */
8
9
10 #include "math2.h"
11 #include "math2.intern.h"
12 #include "keyfile.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 namespace math
18 {
19
20 int count_whitespaces(const char *str, int *line_breaks = 0);
21 void overwrite_comments(char *str) throw(error_obj);
22 int get_word( const char *str, utf8_string &word ) throw(error_obj);
23 void overwrite_script_info(char *str);
24
25
26 const char *reserved_keywords[] = {
27 "Function",
28 "Variable",
29 "Integer",
30 "Real",
31 "Complex",
32 "String",
33 "Matrix",
34 "Picture",
35 "Array",
36 "Boolean",
37 "return",
38 "if",
39 "else",
40 "while",
41 "break",
42 "continue",
43 0
44 };
45
46
check_name_against_reserved(const utf8_string & name)47 void check_name_against_reserved(const utf8_string &name) throw(error_obj)
48 {
49 for(int i=0;;i++)
50 {
51 if(reserved_keywords[i] == 0)
52 break;
53
54 if( name == reserved_keywords[i] )
55 {
56 utf8_string tmpstr( _("Illegal use of reserved keyword: ") );
57 tmpstr.append( name );
58 THROW_ERROR( ErrorType_General, tmpstr.c_str() );
59 }
60 }
61 }
62
63
64
CodeBlockLine()65 CodeBlock::CodeBlockLine::CodeBlockLine()
66 {
67 line_number = 0;
68 type = CodeBlock_Type_Start;
69 sub_type = CodeBlock_SubType_None;
70 code = 0;
71 }
CodeBlockLine(const CodeBlockLine & src)72 CodeBlock::CodeBlockLine::CodeBlockLine(const CodeBlockLine &src) throw(error_obj)
73 {
74 line_number = 0;
75 type = CodeBlock_Type_Start;
76 sub_type = CodeBlock_SubType_None;
77 code = 0;
78
79 *this = src;
80 }
~CodeBlockLine()81 CodeBlock::CodeBlockLine::~CodeBlockLine()
82 {
83 if( type == CodeBlock_Type_Code )
84 delete code;
85 }
operator =(const CodeBlockLine & src)86 void CodeBlock::CodeBlockLine::operator=(const CodeBlockLine &src) throw(error_obj)
87 {
88 if( src.code != 0 && src.type == CodeBlock_Type_Code )
89 {
90 if(code == 0)
91 {
92 try{ code = new CodeLine; }
93 catch(...) { THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
94 }
95
96 try{ *code = *src.code; }
97 catch(...)
98 {
99 delete code;
100 code = 0;
101 throw;
102 }
103 }
104 else
105 {
106 if( type == CodeBlock_Type_Code )
107 {
108 delete code;
109 code = 0;
110 }
111 }
112
113 line_number = src.line_number;
114 type = src.type;
115 sub_type = src.sub_type;
116 }
117
118
119
120
121
122
CodeBlock(const CodeBlock & src)123 CodeBlock::CodeBlock(const CodeBlock &src) throw(error_obj)
124 {
125 inuse = 0;
126 nroftmpvariables = 0;
127 *this = src;
128 }
129
~CodeBlock()130 CodeBlock::~CodeBlock()
131 {
132 lines.clear();
133 }
134
set_code(const char * newcode)135 void CodeBlock::set_code(const char *newcode) throw(error_obj)
136 {
137 char *str;
138
139 clear();
140
141 try{ str = new char [strlen(newcode) + 1]; }
142 catch(...) { THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
143 strcpy(str,newcode);
144
145 try{ set_code_intern( str, true ); }
146 catch(...)
147 {
148 delete [] str;
149 throw;
150 }
151 delete [] str;
152 }
153
set_code_from_file(const utf8_string & new_filename,const utf8_string * only_allow_identifier)154 void CodeBlock::set_code_from_file( const utf8_string &new_filename,
155 const utf8_string *only_allow_identifier ) throw(error_obj)
156 {
157 FILE *fp;
158 long filesize;
159 char *str;
160
161 clear();
162
163 filename = new_filename;
164
165 fp = fopen( filename.c_str(), "rb" );
166 if(fp == 0)
167 {
168 setcode_thrower_error:
169 if(fp != 0)
170 fclose(fp);
171
172 clear();
173 char tmp_err[ERROR_OBJ_MSG_LEN];
174 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't open/read from file (%s)"), new_filename.c_str() );
175 THROW_ERROR( ErrorType_File_IO, tmp_err );
176 }
177
178 if(fseek(fp,0L,SEEK_END) != 0)
179 goto setcode_thrower_error;
180 filesize = ftell(fp);
181 if(filesize == -1)
182 goto setcode_thrower_error;
183 if(fseek(fp,0L,SEEK_SET) != 0)
184 goto setcode_thrower_error;
185
186 try{ str = new char [filesize + 1]; }
187 catch(...)
188 {
189 fclose(fp);
190 THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );
191 }
192
193 if(long(fread(str,1,filesize,fp)) != filesize)
194 {
195 delete [] str;
196 goto setcode_thrower_error;
197 }
198 if(fclose(fp) != 0)
199 {
200 delete [] str;
201 clear();
202 char tmp_err[ERROR_OBJ_MSG_LEN];
203 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Couldn't close file (%s)"), new_filename.c_str() );
204 THROW_ERROR( ErrorType_File_IO, tmp_err );
205 }
206
207 str[filesize] = 0;
208 try
209 {
210 overwrite_comments( str );
211
212 while( create_function( str, only_allow_identifier ) ) { }
213
214 if( str[ count_whitespaces(str) ] != '\0' )
215 {
216 char tmp_err[ERROR_OBJ_MSG_LEN];
217 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Invalid format in file %s"), filename.c_str() );
218 THROW_ERROR( ErrorType_File_IO, tmp_err );
219 }
220 }
221 catch(...)
222 {
223 delete [] str;
224 clear();
225 throw;
226 }
227
228 delete [] str;
229 clear();
230 }
231
calc(Variable * answer)232 void CodeBlock::calc( Variable *answer ) throw(error_obj)
233 {
234 int i;
235 CodeBlock_SubType tmp = CodeBlock_SubType_None;
236 Vector<Variable> tmp_variables;
237 VariableList this_private_varlist;
238
239 tmp_variables.set_size_filled( nroftmpvariables );
240
241 if( answer == 0 )
242 THROW_ERROR( ErrorType_Internal, "No place to store answer in CodeBlock::calc()" );
243
244 try
245 {
246 inuse++;
247
248 i = 0;
249 if( private_varlist.is_empty() )
250 run_block( &tmp_variables, 0, tmp, answer, i );
251 else
252 {
253 this_private_varlist = private_varlist; // makes a private copy of the local variable for the function
254
255 run_block( &tmp_variables, &this_private_varlist, tmp, answer, i );
256 }
257
258 switch( tmp )
259 {
260 case CodeBlock_SubType_None:
261 case CodeBlock_SubType_Return:
262 break;
263
264 case CodeBlock_SubType_Break:
265 THROW_ERROR( ErrorType_General, _("break used outside of while") );
266
267 case CodeBlock_SubType_Continue:
268 THROW_ERROR( ErrorType_General, _("continue used outside of while") );
269
270 default:
271 {
272 char str[50];
273 snprintf( str, 50, "Unhandled CodeBlock_SubType return %ld", tmp );
274
275 THROW_ERROR( ErrorType_Internal, str );
276 }
277 }
278 }
279 catch(error_obj error)
280 {
281 inuse--;
282 if( filename.get_length() == 0 )
283 throw error;
284
285 if( error.type >= ErrorType_UmpCode_General )
286 throw error;
287
288 error_obj error2;
289 error2.type = error.type;
290
291 snprintf( error2.msg, ERROR_OBJ_MSG_LEN, "%s: %s %ld: %s", filename.c_str(), _("line"),
292 lines[i]->line_number, error.msg );
293 throw error2;
294 }
295 catch(...) { inuse--; THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
296
297 inuse--;
298 }
299
clear(void)300 void CodeBlock::clear(void)
301 {
302 try{
303 filename = "";
304 lines.clear();
305 nroftmpvariables = 0;
306 }
307 catch(...) { }
308 }
309
operator =(const CodeBlock & src)310 void CodeBlock::operator=(const CodeBlock &src) throw(error_obj)
311 {
312 printf("\nCodeBlock::operator=() not implemented yet\n");
313 exit(-1);
314 }
315
316
count_whitespaces(const char * str,int * line_breaks)317 int count_whitespaces(const char *str, int *line_breaks)
318 {
319 for(int i=0;;i++)
320 {
321 switch(str[i])
322 {
323 case '\n':
324 if( line_breaks != 0 )
325 line_breaks[0]++;
326 case ' ': case '\t':
327 break;
328 default:
329 return i;
330 }
331 }
332 }
333
334 // this function overwrite all comments with spaces ( \n inside comments are not moved)
335 // \t is also overwritten by one space
overwrite_comments(char * str)336 void overwrite_comments(char *str) throw(error_obj)
337 {
338 int i;
339 bool inside_string = false;
340
341 for(i=0;str[i] != '\0';i++)
342 {
343 if(inside_string)
344 {
345 if( str[i] == '\"' || str[i] == '\n' )
346 inside_string = false;
347 }
348 else
349 {
350 switch(str[i])
351 {
352 case '\"':
353 inside_string = true;
354 break;
355
356 case '\t':
357 str[i] = ' ';
358 break;
359
360 case '#':
361 for(;;i++) // inside a one line comment
362 {
363 str[i] = ' ';
364 if( str[i+1] == '\0' || str[i+1] == '\n' )
365 break;
366 }
367 break;
368
369 case '/':
370 if(str[i+1] == '/') // inside a one line comment
371 {
372 for(;;i++)
373 {
374 str[i] = ' ';
375 if( str[i+1] == '\0' || str[i+1] == '\n' )
376 break;
377 }
378 }
379 else if(str[i+1] == '*') // inside multi line comment
380 {
381 for(;;i++)
382 {
383 if(str[i] != '\n')
384 str[i] = ' ';
385 if(str[i+1] == '\0')
386 THROW_ERROR( ErrorType_General, _("Unexpected end of file") );
387 if( str[i+1] == '*' && str[i+2] == '/' )
388 {
389 str[i+1] = ' ';
390 str[i+2] = ' ';
391 break;
392 }
393 }
394 }
395 break;
396
397 default:
398 break;
399 }
400 }
401 }
402 }
403
get_word(const char * str,utf8_string & word)404 int get_word( const char *str, utf8_string &word ) throw(error_obj)
405 {
406 char tknstr[] = " ";
407 int i=0;
408
409 word = "";
410 if( str[i] >= '0' && str[i] <= '9' )
411 return 0;
412 for(;;i++)
413 {
414 if( (str[i] >= 'A' && str[i] <= 'Z') || (str[i] >= 'a' && str[i] <= 'z') || str[i] == '_' || (str[i] >= '0' && str[i] <= '9') )
415 {
416 tknstr[0] = str[i];
417 word.append( tknstr );
418 }
419 else
420 break;
421 }
422
423 return i;
424 }
425
set_code_intern(char * str,bool allow_variable_creation)426 void CodeBlock::set_code_intern(char *str, bool allow_variable_creation ) throw(error_obj)
427 {
428 utf8_string word;
429 int i, i_tmp;
430 int start = 0;
431 int linenr = 1;
432 int started_curley = 0;
433 int started_bracket = 0;
434 bool inside_string = false;
435 bool end_by_bracket = false;
436 CodeBlock_SubType sub_type = CodeBlock_SubType_None;
437
438 try
439 {
440 for(i=0;;i++)
441 {
442 if( i == start )
443 {
444 i += count_whitespaces( &str[i], &linenr );
445 i_tmp = i + get_word( &str[i], word );
446 if( word == reserved_keywords[reserved_break] )
447 {
448 i = i_tmp;
449 start = i;
450
451 i += count_whitespaces( &str[i], &linenr );
452 if( str[i] == ';' || str[i] == '{' || str[i] == '}' )
453 add_void( CodeBlock_SubType_Break );
454 else
455 {
456 utf8_string tmpstr( _("Illegal use of reserved keyword: ") );
457 tmpstr.append( "break" );
458 THROW_ERROR( ErrorType_General, tmpstr.c_str() );
459 }
460 }
461 else if( word == reserved_keywords[reserved_continue] )
462 {
463 i = i_tmp;
464 start = i;
465
466 i += count_whitespaces( &str[i], &linenr );
467 if( str[i] == ';' || str[i] == '{' || str[i] == '}' )
468 add_void( CodeBlock_SubType_Continue );
469 else
470 {
471 utf8_string tmpstr( _("Illegal use of reserved keyword: ") );
472 tmpstr.append( "continue" );
473 THROW_ERROR( ErrorType_General, tmpstr.c_str() );
474 }
475 }
476 else if( word == reserved_keywords[reserved_return] )
477 {
478 i = i_tmp;
479 start = i;
480
481 i += count_whitespaces( &str[i], &linenr );
482 if( str[i] == ';' || str[i] == '{' || str[i] == '}' )
483 add_void( CodeBlock_SubType_Return );
484 else
485 sub_type = CodeBlock_SubType_Return;
486 }
487 else if( word == reserved_keywords[reserved_while] )
488 {
489 i = i_tmp;
490 i += count_whitespaces( &str[i], &linenr );
491
492 if( str[i] != '(' )
493 THROW_ERROR( ErrorType_General, _("Expected ( after while") );
494
495 started_bracket = 1;
496 end_by_bracket = true;
497 sub_type = CodeBlock_SubType_While;
498
499 i++;
500 start = i;
501 }
502 else if( word == reserved_keywords[reserved_if] )
503 {
504 i = i_tmp;
505 i += count_whitespaces( &str[i], &linenr );
506
507 if( str[i] != '(' )
508 THROW_ERROR( ErrorType_General, _("Expected ( after if") );
509
510 started_bracket = 1;
511 end_by_bracket = true;
512 sub_type = CodeBlock_SubType_If;
513
514 i++;
515 start = i;
516 }
517 else if( word == reserved_keywords[reserved_else] )
518 {
519 i = i_tmp;
520 i += count_whitespaces( &str[i], &linenr );
521
522 add_void( CodeBlock_SubType_Else );
523
524 if( str[i] == '{' )
525 {
526 add_curley( CodeBlock_Type_Start );
527 started_curley++;
528 i++;
529 }
530 else if( str[i] == ';' )
531 {
532 add_curley( CodeBlock_Type_Start ); // adding an empty body
533 add_curley( CodeBlock_Type_Stop );
534 i++;
535 }
536 start = i;
537 i--;
538 continue;
539 }
540 }
541
542 if(inside_string)
543 {
544 if(str[i] == '\"')
545 inside_string = false;
546 else if( str[i] == '\n' || str[i] == '\0' )
547 THROW_ERROR( ErrorType_General, _("Expected ending \"") );
548 }
549 else
550 {
551 switch(str[i])
552 {
553 case '\n':
554 linenr++;
555 break;
556
557 case '\"':
558 inside_string = true;
559 break;
560
561 case '(':
562 started_bracket++;
563 break;
564
565 case ')':
566 started_bracket--;
567 if( started_bracket == 0 && end_by_bracket )
568 {
569 end_by_bracket = false;
570 str[i] = '\0';
571 add_line( &str[start], linenr, allow_variable_creation, sub_type );
572 sub_type = CodeBlock_SubType_None;
573 str[i] = ')';
574 i += 1 + count_whitespaces( &str[i+1], &linenr );
575
576 if( str[i] == ';' )
577 {
578 add_curley( CodeBlock_Type_Start ); // adding an empty body
579 add_curley( CodeBlock_Type_Stop );
580 start = i+1;
581 }
582 else
583 {
584 start = i;
585 i--;
586 }
587 }
588 break;
589
590 case '{':
591 if( end_by_bracket )
592 THROW_ERROR( ErrorType_General, _("Expected ) but found {") );
593 if(start != i)
594 {
595 str[i] = '\0';
596 add_line( &str[start], linenr, allow_variable_creation, sub_type );
597 sub_type = CodeBlock_SubType_None;
598 str[i] = '{';
599 }
600 add_curley( CodeBlock_Type_Start );
601
602 started_curley++;
603
604 start = i+1;
605 break;
606
607 case '}':
608 if( end_by_bracket )
609 THROW_ERROR( ErrorType_General, _("Expected ) but found }") );
610 if(start != i)
611 {
612 str[i] = '\0';
613 add_line( &str[start], linenr, allow_variable_creation, sub_type );
614 sub_type = CodeBlock_SubType_None;
615 str[i] = '}';
616 }
617 add_curley( CodeBlock_Type_Stop );
618
619 if(started_curley == 0)
620 {
621 clear();
622 THROW_ERROR( ErrorType_General, _("Unexpected }") );
623 }
624 started_curley--;
625
626 start = i+1;
627 break;
628
629 case ';':
630 if( end_by_bracket )
631 THROW_ERROR( ErrorType_General, _("Expected ) but found ;") );
632 if(start != i)
633 {
634 str[i] = '\0';
635 add_line( &str[start], linenr, allow_variable_creation, sub_type );
636 sub_type = CodeBlock_SubType_None;
637 str[i] = ';';
638 }
639 start = i+1;
640 break;
641
642 case '\0':
643 if( end_by_bracket )
644 THROW_ERROR( ErrorType_General, _("Expected )") );
645 if(start != i)
646 add_line( &str[start], linenr, allow_variable_creation, sub_type );
647 break;
648 }
649 }
650
651 if(str[i] == '\0')
652 break;
653 }
654 if(started_curley != 0)
655 THROW_ERROR( ErrorType_General, _("Expected }") );
656
657
658 add_automatic_curleys();
659
660
661 for( i=0; i<lines.get_size(); i++ ) // let's check for malplaced else's
662 {
663 if( lines[i]->sub_type == CodeBlock_SubType_Else )
664 {
665 if( i == 0 )
666 THROW_ERROR( ErrorType_General, _("Unexpected 'else'") );
667
668 if( lines[i-1]->type == CodeBlock_Type_Stop )
669 {
670 if( lines[i-1]->pair_with == 0 )
671 THROW_ERROR( ErrorType_General, _("Unexpected 'else'") );
672 if( lines[ lines[i-1]->pair_with -1 ]->sub_type != CodeBlock_SubType_If )
673 THROW_ERROR( ErrorType_General, _("Unexpected 'else'") );
674 }
675 else
676 THROW_ERROR( ErrorType_General, _("Unexpected 'else'") );
677 }
678 }
679
680 for( i=0, nroftmpvariables=0; i<lines.get_size(); i++ ) // updating nroftmpvariables
681 {
682 if( lines[i]->type == CodeBlock_Type_Code )
683 nroftmpvariables = (nroftmpvariables > lines[i]->code->get_nroftmpvariables()) ? nroftmpvariables : lines[i]->code->get_nroftmpvariables();
684 }
685 }
686 catch(error_obj error)
687 {
688 if( filename.get_length() == 0 )
689 {
690 clear();
691 throw error;
692 }
693
694 error_obj error2;
695 error2.type = error.type;
696
697 snprintf( error2.msg, ERROR_OBJ_MSG_LEN, "%s: %s %ld: %s", filename.c_str(), _("line"),
698 linenr, error.msg );
699
700 clear();
701 throw error2;
702 }
703 }
704
add_automatic_curleys(void)705 void CodeBlock::add_automatic_curleys(void) throw(error_obj)
706 {
707 bool added_curley;
708 int i, start;
709
710 i = lines.get_size()-1;
711 if( i == -1 )
712 return;
713
714 if( lines[i]->sub_type == CodeBlock_SubType_While ||
715 lines[i]->sub_type == CodeBlock_SubType_If ||
716 lines[i]->sub_type == CodeBlock_SubType_Else )
717 THROW_ERROR( ErrorType_General, _("Expected {") );
718
719 do
720 {
721 added_curley = false;
722 pair_up_curleys();
723
724 for( i=lines.get_size()-2; i>=0; i-- )
725 {
726 if( lines[i+1]->type != CodeBlock_Type_Start )
727 {
728 if( lines[i]->sub_type == CodeBlock_SubType_While ||
729 lines[i]->sub_type == CodeBlock_SubType_If ||
730 lines[i]->sub_type == CodeBlock_SubType_Else )
731 {
732 i++;
733 start = i;
734
735 if( lines[i]->sub_type == CodeBlock_SubType_While )
736 i = lines[i+1]->pair_with +1;
737 else if( lines[i]->sub_type == CodeBlock_SubType_If )
738 {
739 i = lines[i+1]->pair_with +1;
740 if( lines[i]->sub_type == CodeBlock_SubType_Else )
741 i = lines[i+1]->pair_with +1;
742 }
743 else
744 i++;
745
746 add_curley( CodeBlock_Type_Stop, CodeBlock_SubType_None, i );
747 add_curley( CodeBlock_Type_Start, CodeBlock_SubType_None, start );
748 added_curley = true;
749 break;
750 }
751 }
752 }
753 }while( added_curley );
754 }
755
pair_up_curleys(void)756 void CodeBlock::pair_up_curleys(void)
757 {
758 int i, i_tmp;
759 for( i=0; i<lines.get_size(); i++ )
760 {
761 if( lines[i]->type == CodeBlock_Type_Start ||
762 lines[i]->type == CodeBlock_Type_Stop )
763 lines[i]->pair_with = -1;
764 }
765 for( i=0; i<lines.get_size(); i++ )
766 {
767 if( lines[i]->type == CodeBlock_Type_Stop )
768 {
769 if( lines[i]->pair_with == -1 )
770 {
771 i_tmp = i;
772 for( i--; i>=0; i-- )
773 {
774 if( lines[i]->type == CodeBlock_Type_Start )
775 {
776 if( lines[i]->pair_with == -1 )
777 {
778 lines[i]->pair_with = i_tmp;
779 lines[i_tmp]->pair_with = i;
780 break;
781 }
782 }
783 }
784 }
785 }
786 }
787 }
788
789 // return true if a function was created (and overwrited with spaces, \n are left as is)
790 // if an identifier was found that didn't match with only_allow_identifier, false is returned
create_function(char * str,const utf8_string * only_allow_identifier)791 bool CodeBlock::create_function(char *str, const utf8_string *only_allow_identifier) throw(error_obj)
792 {
793 int i,i_tmp;
794 utf8_string name, word;
795 CodeBlock *func;
796 Vector<ArgumentType> arguments;
797 ArgumentType tmp_argument;
798
799 try
800 {
801 func = new CodeBlock;
802 }
803 catch(...) { THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
804
805 try
806 {
807 i = count_whitespaces( str ); // skipping whitespaces
808 if(str[i] == '\0')
809 {
810 delete func;
811 return false;
812 }
813
814 // Checking for "Function"
815 i += get_word( &str[i], word );
816 if( word != reserved_keywords[reserved_function] )
817 {
818 delete func;
819 return false;
820 }
821
822 if( (i_tmp = count_whitespaces( &str[i] )) == 0 )
823 {
824 delete func;
825 return false; // keyword "Function" must be followed by whitespace(s)
826 }
827 i += i_tmp;
828 // Found "Function"
829
830 // Getting name of function
831 i += get_word( &str[i], name );
832
833 // Check so that the name is allowed
834 if( only_allow_identifier != 0 )
835 {
836 if( name != *only_allow_identifier )
837 {
838 delete func;
839 return false;
840 }
841 }
842
843 // Make sure the name is legal and unique
844 check_name_against_reserved( name );
845
846 if( function_list.check_for( name ) )
847 {
848 error_obj error;
849
850 error.type = ErrorType_Name_isnt_unique;
851 snprintf( error.msg, ERROR_OBJ_MSG_LEN, "Function name (%s) is not unique", name.c_str() );
852 throw error;
853 }
854
855 try
856 {
857 global_varlist.get_id( name.c_str() ); // this line will throw if the name isn't a Variable
858 error_obj error;
859 error.type = ErrorType_Name_isnt_unique;
860 snprintf( error.msg, ERROR_OBJ_MSG_LEN, "Function name (%s) is not unique", name.c_str() );
861 throw error;
862 }
863 catch(error_obj error) // only throwed error is 'Variable not found' and 'Function name () is not unique'
864 {
865 if( error.type == ErrorType_Name_isnt_unique )
866 throw;
867 }
868 // The name is now legal and unique
869
870 // Now its time for the argument brackets
871 i += count_whitespaces( &str[i] );
872 if(str[i] == '(') // checking if the function should have arguments
873 {
874 for(i++;;)
875 {
876 i += count_whitespaces( &str[i] );
877
878 get_word( &str[i], word );
879 if( word.get_length() != 0 )
880 {
881 if( word == reserved_keywords[reserved_variable] )
882 {
883 tmp_argument.type = reserved_variable;
884 specified_argument_entry:
885 i += word.get_length();
886 i += count_whitespaces( &str[i] );
887 get_word( &str[i], word );
888 unspecified_argument_entry:
889 i += word.get_length();
890 i += count_whitespaces( &str[i] );
891
892 check_name_against_reserved( word );
893 if( word == "i" )
894 THROW_ERROR( ErrorType_General, _("\'i\' isn't a valid name of an argument variable.") );
895
896 try{
897 func->private_varlist.get_id( word.c_str() );
898 word.prepend( _("Name is not unique: ") );
899 THROW_ERROR( ErrorType_Name_isnt_unique, word.c_str() );
900 }
901 catch(error_obj error) // only throwed error is 'Variable not found' and 'Name is not unique'
902 {
903 if( error.type == ErrorType_Name_isnt_unique )
904 throw;
905
906 try{ tmp_argument.variable_name = word; }
907 catch(...) { THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
908
909 arguments.append( tmp_argument );
910
911 Variable tmpvar;
912 tmpvar.set_name( word );
913 func->private_varlist.create( tmpvar, false, false, true );
914 }
915 if( str[i] == ')' )
916 break;
917 else if( str[i] == ',' )
918 i++;
919 }
920 else if( word == reserved_keywords[reserved_integer] )
921 {
922 tmp_argument.type = reserved_integer;
923 goto specified_argument_entry;
924 }
925 else if( word == reserved_keywords[reserved_real] )
926 {
927 tmp_argument.type = reserved_real;
928 goto specified_argument_entry;
929 }
930 else if( word == reserved_keywords[reserved_complex] )
931 {
932 tmp_argument.type = reserved_complex;
933 goto specified_argument_entry;
934 }
935 else if( word == reserved_keywords[reserved_string] )
936 {
937 tmp_argument.type = reserved_string;
938 goto specified_argument_entry;
939 }
940 else if( word == reserved_keywords[reserved_matrix] )
941 {
942 tmp_argument.type = reserved_matrix;
943 goto specified_argument_entry;
944 }
945 else if( word == reserved_keywords[reserved_picture] )
946 {
947 tmp_argument.type = reserved_picture;
948 goto specified_argument_entry;
949 }
950 else if( word == reserved_keywords[reserved_array] )
951 {
952 tmp_argument.type = reserved_array;
953 goto specified_argument_entry;
954 }
955 else if( word == reserved_keywords[reserved_boolean] )
956 {
957 tmp_argument.type = reserved_boolean;
958 goto specified_argument_entry;
959 }
960 else
961 {
962 // this is an unspecified argument make it the same as Variable
963 tmp_argument.type = reserved_variable;
964 goto unspecified_argument_entry;
965 }
966 }
967 else
968 {
969 if( arguments.get_size() != 0 )
970 THROW_ERROR( ErrorType_General, _("Expected argument") );
971
972 if( str[i] == '\0' )
973 {
974 THROW_ERROR( ErrorType_General, _("Expected )") );
975 }
976 else if( str[i] == ')' )
977 break;
978 else
979 THROW_ERROR( ErrorType_General, _("Syntax error") );
980 }
981 }
982 i += 1 + count_whitespaces( &str[i+1] );
983 }
984 // Argument brackets handled
985
986 // Function body start
987 if(str[i] != '{')
988 THROW_ERROR( ErrorType_General, _("Expected {") );
989 i++;
990
991 // The functions intern variables should be created
992 for(;;)
993 {
994 i += count_whitespaces( &str[i] );
995
996 get_word( &str[i], word );
997 i += word.get_length();
998 if( word == reserved_keywords[reserved_variable] )
999 {
1000 do
1001 {
1002 i += count_whitespaces( &str[i] );
1003
1004 i += get_word( &str[i], word );
1005
1006 check_name_against_reserved( word );
1007 if( word == "i" )
1008 THROW_ERROR( ErrorType_General, _("\'i\' isn't a valid name of an intern variable.") );
1009
1010 try{
1011 func->private_varlist.get_id( word.c_str() );
1012
1013 word.prepend( _("Name is not unique: ") );
1014 THROW_ERROR( ErrorType_Name_isnt_unique, word.c_str() );
1015 }
1016 catch(error_obj error) // only throwed error is 'Variable not found' and 'Name is not unique'
1017 {
1018 if( error.type == ErrorType_Name_isnt_unique )
1019 throw;
1020
1021 Variable tmpvar;
1022 tmpvar.set_name( word );
1023 func->private_varlist.create( tmpvar, false, false, true );
1024 }
1025 i += count_whitespaces( &str[i] );
1026 if( str[i] == ',' )
1027 i++;
1028 else if( str[i] == ';' )
1029 {
1030 i++;
1031 break;
1032 }
1033 else
1034 THROW_ERROR( ErrorType_General, _("Expected ;") );
1035 }while( true );
1036 }
1037 else
1038 {
1039 i -= word.get_length();
1040 break;
1041 }
1042 }
1043 // All intern variable has been created
1044
1045
1046 {
1047 bool inside_string = false;
1048 int nested_blocks = 0;
1049 for(i_tmp=0;;i_tmp++) // getting the length of the function
1050 {
1051 if(str[i+i_tmp] == '\0')
1052 THROW_ERROR( ErrorType_General, _("Expected }") );
1053
1054 if(inside_string)
1055 {
1056 if(str[i+i_tmp] == '\"')
1057 inside_string = false;
1058 }
1059 else
1060 {
1061 if(str[i+i_tmp] == '{')
1062 nested_blocks++;
1063 else if(str[i+i_tmp] == '}')
1064 {
1065 if(nested_blocks == 0)
1066 break;
1067 else
1068 nested_blocks--;
1069 }
1070 else if(str[i+i_tmp] == '\"')
1071 inside_string = true;
1072 }
1073 }
1074 }
1075 // Function body ended
1076
1077 for(int i2=0; i2 < i; i2++ ) // overwriting "Function name(){" with spaces
1078 {
1079 if( str[i2] != '\n' )
1080 str[i2] = ' ';
1081 }
1082
1083 }
1084 catch(error_obj error)
1085 {
1086 error_obj error2;
1087 int linenr = 1;
1088 error2.type = error.type;
1089
1090 delete func;
1091
1092 for( i_tmp=0; i_tmp < i; i_tmp++ )
1093 {
1094 if( str[i_tmp] == '\n' )
1095 linenr++;
1096 }
1097
1098 snprintf( error2.msg, ERROR_OBJ_MSG_LEN, "%s: %s %ld: %s", filename.c_str(), _("line"),
1099 linenr, error.msg );
1100 throw error2;
1101 }
1102
1103
1104 str[i+i_tmp] = '\0'; // overwriting the ending '}'
1105
1106 try{ func->filename = filename; }
1107 catch(...) { } // don't care about this error, 'cause it just disables filename in error-msg
1108
1109 try
1110 {
1111 // Temporary adding a dummy function (to be able to have recursive calls)
1112 function_list.add_this_code_block_function( name, 0, arguments );
1113
1114 try{ func->set_code_intern( str, false ); }
1115 catch(...)
1116 {
1117 function_list.delete_function( name );
1118 throw;
1119 }
1120
1121 // Removing the dummy function added
1122 function_list.delete_function( name );
1123
1124 function_list.add_this_code_block_function( name, func, arguments );
1125 }
1126 catch(...)
1127 {
1128 delete func;
1129 throw;
1130 }
1131
1132 for(int i2=i; i2 <= (i+i_tmp); i2++ ) // overwriting the whole function with spaces
1133 {
1134 if( str[i2] != '\n' )
1135 str[i2] = ' ';
1136 }
1137
1138 return true;
1139 }
1140
add_line(const char * codeline,int linenr,bool allow_variable_creation,CodeBlock_SubType sub_type)1141 void CodeBlock::add_line(const char *codeline, int linenr, bool allow_variable_creation,
1142 CodeBlock_SubType sub_type) throw(error_obj)
1143 {
1144 CodeBlockLine *line = 0;
1145
1146 try
1147 {
1148 try
1149 {
1150 line = new CodeBlockLine;
1151 lines.append_this( line );
1152 }
1153 catch(...)
1154 {
1155 delete line;
1156 throw;
1157 }
1158
1159 line->line_number = linenr;
1160 line->type = CodeBlock_Type_Code;
1161 line->sub_type = sub_type;
1162
1163 line->code = new CodeLine;
1164 if( private_varlist.is_empty() )
1165 line->code->set_code_line( codeline, allow_variable_creation, 0 );
1166 else
1167 line->code->set_code_line( codeline, allow_variable_creation, &private_varlist );
1168
1169 if( line->code->is_empty() )
1170 lines.remove( lines.get_size()-1 );
1171 }
1172 catch(error_obj error) { throw; }
1173 catch(...) { THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
1174 }
1175
add_curley(CodeBlock_Type type,CodeBlock_SubType sub_type,int pos)1176 void CodeBlock::add_curley(CodeBlock_Type type, CodeBlock_SubType sub_type, int pos) throw(error_obj)
1177 {
1178 CodeBlockLine *line = 0;
1179
1180 try
1181 {
1182 try
1183 {
1184 line = new CodeBlockLine;
1185 lines.insert_this( line, pos );
1186 }
1187 catch(...)
1188 {
1189 delete line;
1190 throw;
1191 }
1192
1193 line->type = type;
1194 line->sub_type = sub_type;
1195 line->pair_with = -1;
1196 }
1197 catch(...) { THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
1198 }
1199
add_void(CodeBlock_SubType sub_type)1200 void CodeBlock::add_void( CodeBlock_SubType sub_type ) throw(error_obj)
1201 {
1202 CodeBlockLine *line = 0;
1203
1204 try
1205 {
1206 try
1207 {
1208 line = new CodeBlockLine;
1209 lines.append_this( line );
1210 }
1211 catch(...)
1212 {
1213 delete line;
1214 throw;
1215 }
1216
1217 line->type = CodeBlock_Type_Void;
1218 line->sub_type = sub_type;
1219 }
1220 catch(...) { THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
1221 }
1222
run_block(Vector<Variable> * tmp_variables,VariableList * this_private_varlist,CodeBlock_SubType & ret,Variable * ans,int & start,bool expect_curley_ending) const1223 void CodeBlock::run_block( Vector<Variable> *tmp_variables, VariableList *this_private_varlist, CodeBlock_SubType &ret,
1224 Variable *ans, int &start, bool expect_curley_ending ) const throw(error_obj)
1225 {
1226 Variable *tmp;
1227
1228 for( ; start<lines.get_size(); start++ )
1229 {
1230 switch( lines[start]->type )
1231 {
1232 case CodeBlock_Type_Code:
1233 if( start == (lines.get_size()-1) )
1234 tmp = ans;
1235 else
1236 {
1237 switch( lines[start]->sub_type )
1238 {
1239 case CodeBlock_SubType_If:
1240 case CodeBlock_SubType_While:
1241 case CodeBlock_SubType_Return:
1242 tmp = ans;
1243 break;
1244 default:
1245 tmp = 0;
1246 }
1247 }
1248 lines[start]->code->calc( tmp, this_private_varlist, tmp_variables );
1249
1250 if( tmp != 0 )
1251 {
1252 switch( lines[start]->sub_type )
1253 {
1254 case CodeBlock_SubType_Return:
1255 ret = CodeBlock_SubType_Return;
1256 return;
1257
1258 case CodeBlock_SubType_While:
1259 {
1260 int tmp;
1261
1262 if( ans->get_type() != VariableType_Boolean )
1263 {
1264 char tmp_err[ERROR_OBJ_MSG_LEN];
1265 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Data type is unsupported by '%s'"), "while" );
1266 THROW_ERROR( ErrorType_General, tmp_err );
1267 }
1268
1269 if( ans->get_boolean() )
1270 { // lets run the 'while'-block
1271 tmp = start;
1272 start += 2;
1273 run_block( tmp_variables, this_private_varlist, ret, ans, start, true );
1274 switch( ret )
1275 {
1276 case CodeBlock_SubType_None:
1277 case CodeBlock_SubType_Continue:
1278 start = tmp-1;
1279 break;
1280
1281 case CodeBlock_SubType_Break:
1282 start = lines[tmp+1]->pair_with;
1283 break;
1284
1285 case CodeBlock_SubType_Return:
1286 return;
1287 }
1288 ret = CodeBlock_SubType_None;
1289 }
1290 else // lets skip the 'while'-block
1291 start = lines[start+1]->pair_with;
1292 }
1293 break;
1294
1295 case CodeBlock_SubType_If:
1296 if( ans->get_type() != VariableType_Boolean )
1297 {
1298 char tmp_err[ERROR_OBJ_MSG_LEN];
1299 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Data type is unsupported by '%s'"), "if" );
1300 THROW_ERROR( ErrorType_General, tmp_err );
1301 }
1302
1303 if( ans->get_boolean() )
1304 { // lets run the 'if'-block
1305 start += 2;
1306 run_block( tmp_variables, this_private_varlist, ret, ans, start, true );
1307 if( ret != CodeBlock_SubType_None )
1308 return;
1309 // 'if' was followed by 'else', lets skip that block
1310 if( lines.get_size() > start+2 )
1311 if( lines[start+1]->sub_type == CodeBlock_SubType_Else )
1312 start = lines[start+2]->pair_with;
1313 }
1314 else
1315 { // lets skip the 'if'-block
1316 start = lines[start+1]->pair_with;
1317 // 'if' was followed by 'else', lets run that block
1318 if( lines.get_size() > start+1 )
1319 {
1320 if( lines[start+1]->sub_type == CodeBlock_SubType_Else )
1321 {
1322 start += 3; // this skips } else {
1323 run_block( tmp_variables, this_private_varlist, ret, ans, start, true );
1324 if( ret != CodeBlock_SubType_None )
1325 return;
1326 }
1327 }
1328 }
1329 break;
1330
1331 default:
1332 break;
1333 }
1334 }
1335 break;
1336
1337 case CodeBlock_Type_Start:
1338 start++;
1339 run_block( tmp_variables, this_private_varlist, ret, ans, start, true );
1340 if( ret != CodeBlock_SubType_None )
1341 return;
1342 break;
1343
1344 case CodeBlock_Type_Stop:
1345 if( expect_curley_ending )
1346 return;
1347 THROW_ERROR( ErrorType_General, _("Unexpected }") );
1348
1349 case CodeBlock_Type_Void:
1350 switch( lines[start]->sub_type )
1351 {
1352 case CodeBlock_SubType_Return:
1353 ans->set_void();
1354 ret = CodeBlock_SubType_Return;
1355 return;
1356
1357 case CodeBlock_SubType_Break:
1358 ret = CodeBlock_SubType_Break;
1359 return;
1360
1361 case CodeBlock_SubType_Continue:
1362 ret = CodeBlock_SubType_Continue;
1363 return;
1364
1365 case CodeBlock_SubType_None:
1366 break;
1367
1368 default:
1369 printf("not yet implemented CodeBlock_Type_Void with sub_type: %ld\n", lines[start]->sub_type);
1370 }
1371 break;
1372 }
1373 }
1374 }
1375
1376 } // namespace math
1377