# HG changeset patch # User Mario de Sousa # Date 1311951808 -3600 # Node ID 2c3c4dc34979942a06d4423b43962a1c34028caf # Parent ba80c3ceb6fbcafca2aa0459e3cf5845cb8aabc8 Support for semantic verification of calls to standard functions. This commit makes a fundamental change in the way standard functions are handled by the compiler. diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax/absyntax.cc --- a/absyntax/absyntax.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax/absyntax.cc Fri Jul 29 16:03:28 2011 +0100 @@ -41,10 +41,11 @@ //#include "../stage1_2/iec.hh" /* required for BOGUS_TOKEN_ID, etc... */ #include "visitor.hh" -#define ABORT(str) {printf("ERROR: %s\n", str); exit(0);} - - - +#define ERROR error_exit(__FILE__,__LINE__) +/* function defined in main.cc */ +extern void error_exit(const char *file_name, int line_no); + +#define ABORT(str) {printf("ERROR: %s\n", str); ERROR;} @@ -94,7 +95,7 @@ add_element(elem); } -/* insert a new element */ +/* append a new element to the end of the list */ void list_c::add_element(symbol_c *elem) { //printf("list_c::add_element()\n"); n++; @@ -125,10 +126,24 @@ } } - - - -#define SYM_LIST(class_name_c) \ +/* insert a new element before position pos. */ +/* To insert into the begining of list, call with pos=0 */ +/* To insert into the end of list, call with pos=list->n */ +void list_c::insert_element(symbol_c *elem, int pos) { + int i; + if (pos > n) ERROR; + + /* add new element to end of list. Basically alocate required memory... */ + /* will also increment n by 1 ! */ + add_element(elem); + /* if not inserting into end position, shift all elements up one position, to open up a slot in pos for new element */ + if (pos < (n-1)) for (i = n-2; i >= pos; i--) elements[i+1] = elements[i]; + elements[pos] = elem; +} + + + +#define SYM_LIST(class_name_c, ...) \ class_name_c::class_name_c( \ int fl, int fc, const char *ffile, long int forder, \ int ll, int lc, const char *lfile, long int lorder) \ @@ -139,14 +154,14 @@ :list_c(elem, fl, fc, ffile, forder, ll, lc, lfile, lorder) {} \ void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} -#define SYM_TOKEN(class_name_c) \ +#define SYM_TOKEN(class_name_c, ...) \ class_name_c::class_name_c(const char *value, \ int fl, int fc, const char *ffile, long int forder, \ int ll, int lc, const char *lfile, long int lorder) \ :token_c(value, fl, fc, ffile, forder, ll, lc, lfile, lorder) {} \ void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} -#define SYM_REF0(class_name_c) \ +#define SYM_REF0(class_name_c, ...) \ class_name_c::class_name_c( \ int fl, int fc, const char *ffile, long int forder, \ int ll, int lc, const char *lfile, long int lorder) \ @@ -154,43 +169,43 @@ void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} -#define SYM_REF1(class_name_c, ref1) \ -class_name_c::class_name_c(symbol_c *ref1, \ - int fl, int fc, const char *ffile, long int forder, \ - int ll, int lc, const char *lfile, long int lorder) \ - :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \ - this->ref1 = ref1; \ -} \ -void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} - - -#define SYM_REF2(class_name_c, ref1, ref2) \ -class_name_c::class_name_c(symbol_c *ref1, \ - symbol_c *ref2, \ - int fl, int fc, const char *ffile, long int forder, \ - int ll, int lc, const char *lfile, long int lorder) \ - :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \ - this->ref1 = ref1; \ - this->ref2 = ref2; \ -} \ -void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} - - -#define SYM_REF3(class_name_c, ref1, ref2, ref3) \ -class_name_c::class_name_c(symbol_c *ref1, \ - symbol_c *ref2, \ - symbol_c *ref3, \ - int fl, int fc, const char *ffile, long int forder, \ - int ll, int lc, const char *lfile, long int lorder) \ - :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \ - this->ref1 = ref1; \ - this->ref2 = ref2; \ - this->ref3 = ref3; \ -} \ -void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} - - -#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \ +#define SYM_REF1(class_name_c, ref1, ...) \ +class_name_c::class_name_c(symbol_c *ref1, \ + int fl, int fc, const char *ffile, long int forder, \ + int ll, int lc, const char *lfile, long int lorder) \ + :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \ + this->ref1 = ref1; \ +} \ +void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} + + +#define SYM_REF2(class_name_c, ref1, ref2, ...) \ +class_name_c::class_name_c(symbol_c *ref1, \ + symbol_c *ref2, \ + int fl, int fc, const char *ffile, long int forder, \ + int ll, int lc, const char *lfile, long int lorder) \ + :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \ + this->ref1 = ref1; \ + this->ref2 = ref2; \ +} \ +void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} + + +#define SYM_REF3(class_name_c, ref1, ref2, ref3, ...) \ +class_name_c::class_name_c(symbol_c *ref1, \ + symbol_c *ref2, \ + symbol_c *ref3, \ + int fl, int fc, const char *ffile, long int forder, \ + int ll, int lc, const char *lfile, long int lorder) \ + :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \ + this->ref1 = ref1; \ + this->ref2 = ref2; \ + this->ref3 = ref3; \ +} \ +void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} + + +#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4, ...) \ class_name_c::class_name_c(symbol_c *ref1, \ symbol_c *ref2, \ symbol_c *ref3, \ @@ -206,7 +221,7 @@ void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} -#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5) \ +#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5, ...) \ class_name_c::class_name_c(symbol_c *ref1, \ symbol_c *ref2, \ symbol_c *ref3, \ @@ -225,7 +240,7 @@ -#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \ +#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6, ...) \ class_name_c::class_name_c(symbol_c *ref1, \ symbol_c *ref2, \ symbol_c *ref3, \ diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax/absyntax.def --- a/absyntax/absyntax.def Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax/absyntax.def Fri Jul 29 16:03:28 2011 +0100 @@ -538,6 +538,33 @@ /* | var1_list ',' variable_name */ SYM_LIST(var1_list_c) +/* | [var1_list ','] variable_name integer '..' */ +/* NOTE: This is an extension to the standard!!! */ +/* In order to be able to handle extensible standard functions + * (i.e. standard functions that may have a variable number of + * input parameters, such as AND(word#33, word#44, word#55, word#66), + * we have extended the acceptable syntax to allow var_name '..' + * in an input variable declaration. + * + * This allows us to parse the declaration of standard + * extensible functions and load their interface definition + * into the abstract syntax tree just like we do to other + * user defined functions. + * This has the advantage that we can later do semantic + * checking of calls to functions (be it a standard or user defined + * function) in (almost) exactly the same way. + * + * The integer tells the compiler the number of the first parameter. + * for example, for ADD(IN1 := 11, IN2:=22), the index for IN starts off at 1. + * Some other standard library functions, such as MUX, has the extensible + * variable starting off from 0 (IN0, IN1, IN2, ...). + * + * Of course, we have a flag that disables this syntax when parsing user + * written code, so we only allow this extra syntax while parsing the + * 'header' file that declares all the standard IEC 61131-3 functions. + */ +SYM_REF2(extensible_input_parameter_c, var_name, first_index) + /* var1_list ':' array_spec_init */ SYM_REF2(array_var_init_decl_c, var1_list, array_spec_init) @@ -632,7 +659,15 @@ /* STRING ['[' integer ']'] [ASSIGN single_byte_character_string] */ /* integer ->may be NULL ! */ /* single_byte_character_string ->may be NULL ! */ -SYM_REF2(single_byte_string_spec_c, integer, single_byte_character_string) +SYM_REF2(single_byte_string_spec_c, string_spec, single_byte_character_string) + +/* STRING ['[' integer ']'] */ +/* integer ->may be NULL ! */ +SYM_REF2(single_byte_limited_len_string_spec_c, string_type_name, character_string_len) + +/* WSTRING ['[' integer ']'] */ +/* integer ->may be NULL ! */ +SYM_REF2(double_byte_limited_len_string_spec_c, string_type_name, character_string_len) /* var1_list ':' double_byte_string_spec */ SYM_REF2(double_byte_string_var_declaration_c, var1_list, double_byte_string_spec) @@ -640,7 +675,7 @@ /* WSTRING ['[' integer ']'] [ASSIGN double_byte_character_string] */ /* integer ->may be NULL ! */ /* double_byte_character_string ->may be NULL ! */ -SYM_REF2(double_byte_string_spec_c, integer, double_byte_character_string) +SYM_REF2(double_byte_string_spec_c, string_spec, double_byte_character_string) /*| VAR [RETAIN|NON_RETAIN] incompl_located_var_decl_list END_VAR */ /* option ->may be NULL ! */ @@ -885,7 +920,10 @@ SYM_REF2(il_simple_operation_c, il_simple_operator, il_operand) /* | function_name [il_operand_list] */ -SYM_REF2(il_function_call_c, function_name, il_operand_list) +/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. + * See the comment above function_invocation_c for more details + */ +SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;) /* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */ @@ -904,7 +942,10 @@ /* | function_name '(' eol_list [il_param_list] ')' */ -SYM_REF2(il_formal_funct_call_c, function_name, il_param_list) +/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. + * See the comment above function_invocation_c for more details + */ +SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;) /* | il_operand_list ',' il_operand */ SYM_LIST(il_operand_list_c) @@ -1004,7 +1045,17 @@ /* formal_param_list -> may be NULL ! */ /* nonformal_param_list -> may be NULL ! */ -SYM_REF3(function_invocation_c, function_name, formal_param_list, nonformal_param_list) +/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. + * The IEC 61131-3 standard allows for overloaded standard functions. This means that some + * function calls are not compeletely defined by the name of the function being called, + * and need to be disambiguated with using the data types of the parameters being passed. + * Stage 3 does this to verify semantic correctnes. + * Stage 4 also needs to do this in order to determine which function to call. + * It does not make sense to determine the exact function being called twice (once in stage 3, + * and again in stage 4), so stage 3 will store this infor in the parameter called_function_declaration + * for stage 4 to use it later on. + */ +SYM_REF3(function_invocation_c, function_name, formal_param_list, nonformal_param_list, symbol_c *called_function_declaration; int extensible_param_count;) /********************/ diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax/absyntax.hh --- a/absyntax/absyntax.hh Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax/absyntax.hh Fri Jul 29 16:03:28 2011 +0100 @@ -119,16 +119,22 @@ int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, /* order in which it is read by lexcial analyser */ int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0 /* order in which it is read by lexcial analyser */ ); - /* insert a new element */ + /* append a new element to the end of the list */ virtual void add_element(symbol_c *elem); -}; - - - - -#define SYM_LIST(class_name_c) \ + /* insert a new element before position pos. */ + /* To insert into the begining of list, call with pos=0 */ + /* To insert into the end of list, call with pos=list->n */ + virtual void insert_element(symbol_c *elem, int pos = 0); +}; + + + + +#define SYM_LIST(class_name_c, ...) \ class class_name_c: public list_c { \ public: \ + __VA_ARGS__ \ + public: \ class_name_c( \ int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ @@ -139,9 +145,11 @@ }; -#define SYM_TOKEN(class_name_c) \ +#define SYM_TOKEN(class_name_c, ...) \ class class_name_c: public token_c { \ public: \ + __VA_ARGS__ \ + public: \ class_name_c(const char *value, \ int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ @@ -149,8 +157,10 @@ }; -#define SYM_REF0(class_name_c) \ -class class_name_c: public symbol_c { \ +#define SYM_REF0(class_name_c, ...) \ +class class_name_c: public symbol_c { \ + public: \ + __VA_ARGS__ \ public: \ class_name_c( \ int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ @@ -159,23 +169,25 @@ }; -#define SYM_REF1(class_name_c, ref1) \ -class class_name_c: public symbol_c { \ - public: \ - symbol_c *ref1; \ - public: \ - class_name_c(symbol_c *ref1, \ - int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ - int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ - virtual void *accept(visitor_c &visitor); \ -}; - - -#define SYM_REF2(class_name_c, ref1, ref2) \ -class class_name_c: public symbol_c { \ - public: \ - symbol_c *ref1; \ - symbol_c *ref2; \ +#define SYM_REF1(class_name_c, ref1, ...) \ +class class_name_c: public symbol_c { \ + public: \ + symbol_c *ref1; \ + __VA_ARGS__ \ + public: \ + class_name_c(symbol_c *ref1, \ + int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ + int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ + virtual void *accept(visitor_c &visitor); \ +}; + + +#define SYM_REF2(class_name_c, ref1, ref2, ...) \ +class class_name_c: public symbol_c { \ + public: \ + symbol_c *ref1; \ + symbol_c *ref2; \ + __VA_ARGS__ \ public: \ class_name_c(symbol_c *ref1, \ symbol_c *ref2 = NULL, \ @@ -185,29 +197,31 @@ }; -#define SYM_REF3(class_name_c, ref1, ref2, ref3) \ -class class_name_c: public symbol_c { \ - public: \ - symbol_c *ref1; \ - symbol_c *ref2; \ - symbol_c *ref3; \ - public: \ - class_name_c(symbol_c *ref1, \ - symbol_c *ref2, \ - symbol_c *ref3, \ - int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ - int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ - virtual void *accept(visitor_c &visitor); \ -}; - - -#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \ +#define SYM_REF3(class_name_c, ref1, ref2, ref3, ...) \ +class class_name_c: public symbol_c { \ + public: \ + symbol_c *ref1; \ + symbol_c *ref2; \ + symbol_c *ref3; \ + __VA_ARGS__ \ + public: \ + class_name_c(symbol_c *ref1, \ + symbol_c *ref2, \ + symbol_c *ref3, \ + int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ + int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ + virtual void *accept(visitor_c &visitor); \ +}; + + +#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4, ...) \ class class_name_c: public symbol_c { \ public: \ symbol_c *ref1; \ symbol_c *ref2; \ symbol_c *ref3; \ symbol_c *ref4; \ + __VA_ARGS__ \ public: \ class_name_c(symbol_c *ref1, \ symbol_c *ref2, \ @@ -219,7 +233,7 @@ }; -#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5) \ +#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5, ...) \ class class_name_c: public symbol_c { \ public: \ symbol_c *ref1; \ @@ -227,6 +241,7 @@ symbol_c *ref3; \ symbol_c *ref4; \ symbol_c *ref5; \ + __VA_ARGS__ \ public: \ class_name_c(symbol_c *ref1, \ symbol_c *ref2, \ @@ -239,7 +254,7 @@ }; -#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \ +#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6, ...) \ class class_name_c: public symbol_c { \ public: \ symbol_c *ref1; \ @@ -248,6 +263,7 @@ symbol_c *ref4; \ symbol_c *ref5; \ symbol_c *ref6; \ + __VA_ARGS__ \ public: \ class_name_c(symbol_c *ref1, \ symbol_c *ref2, \ diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax/visitor.cc --- a/absyntax/visitor.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax/visitor.cc Fri Jul 29 16:03:28 2011 +0100 @@ -82,19 +82,19 @@ #define SYM_REF1(class_name_c, ref1) \ void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} -#define SYM_REF2(class_name_c, ref1, ref2) \ - void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} - -#define SYM_REF3(class_name_c, ref1, ref2, ref3) \ - void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} - -#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \ - void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} - -#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5) \ - void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} - -#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \ +#define SYM_REF2(class_name_c, ref1, ref2, ...) \ + void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} + +#define SYM_REF3(class_name_c, ref1, ref2, ref3, ...) \ + void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} + +#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4, ...) \ + void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} + +#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5, ...) \ + void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} + +#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6, ...) \ void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} @@ -148,31 +148,31 @@ return NULL; \ } -#define SYM_REF2(class_name_c, ref1, ref2) \ +#define SYM_REF2(class_name_c, ref1, ref2, ...) \ void *iterator_visitor_c::visit(class_name_c *symbol) { \ if (symbol->ref1!=NULL) symbol->ref1->accept(*this); \ if (symbol->ref2!=NULL) symbol->ref2->accept(*this); \ return NULL; \ } -#define SYM_REF3(class_name_c, ref1, ref2, ref3) \ -void *iterator_visitor_c::visit(class_name_c *symbol) { \ - if (symbol->ref1) symbol->ref1->accept(*this); \ - if (symbol->ref2) symbol->ref2->accept(*this); \ - if (symbol->ref3) symbol->ref3->accept(*this); \ - return NULL; \ -} - -#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \ -void *iterator_visitor_c::visit(class_name_c *symbol) { \ - if (symbol->ref1) symbol->ref1->accept(*this); \ - if (symbol->ref2) symbol->ref2->accept(*this); \ - if (symbol->ref3) symbol->ref3->accept(*this); \ - if (symbol->ref4) symbol->ref4->accept(*this); \ - return NULL; \ -} - -#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5) \ +#define SYM_REF3(class_name_c, ref1, ref2, ref3, ...) \ +void *iterator_visitor_c::visit(class_name_c *symbol) { \ + if (symbol->ref1) symbol->ref1->accept(*this); \ + if (symbol->ref2) symbol->ref2->accept(*this); \ + if (symbol->ref3) symbol->ref3->accept(*this); \ + return NULL; \ +} + +#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4, ...) \ +void *iterator_visitor_c::visit(class_name_c *symbol) { \ + if (symbol->ref1) symbol->ref1->accept(*this); \ + if (symbol->ref2) symbol->ref2->accept(*this); \ + if (symbol->ref3) symbol->ref3->accept(*this); \ + if (symbol->ref4) symbol->ref4->accept(*this); \ + return NULL; \ +} + +#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5, ...) \ void *iterator_visitor_c::visit(class_name_c *symbol) { \ if (symbol->ref1) symbol->ref1->accept(*this); \ if (symbol->ref2) symbol->ref2->accept(*this); \ @@ -182,7 +182,7 @@ return NULL; \ } -#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \ +#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6, ...) \ void *iterator_visitor_c::visit(class_name_c *symbol) { \ if (symbol->ref1) symbol->ref1->accept(*this); \ if (symbol->ref2) symbol->ref2->accept(*this); \ @@ -250,7 +250,7 @@ return NULL; \ } -#define SYM_REF2(class_name_c, ref1, ref2) \ +#define SYM_REF2(class_name_c, ref1, ref2, ...) \ void *search_visitor_c::visit(class_name_c *symbol) { \ void *res = NULL; \ if (symbol->ref1) res = symbol->ref1->accept(*this); \ @@ -259,7 +259,7 @@ return NULL; \ } -#define SYM_REF3(class_name_c, ref1, ref2, ref3) \ +#define SYM_REF3(class_name_c, ref1, ref2, ref3, ...) \ void *search_visitor_c::visit(class_name_c *symbol) { \ void *res = NULL; \ if (symbol->ref1) res = symbol->ref1->accept(*this); \ @@ -270,7 +270,7 @@ return NULL; \ } -#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \ +#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4, ...) \ void *search_visitor_c::visit(class_name_c *symbol) { \ void *res = NULL; \ if (symbol->ref1) res = symbol->ref1->accept(*this); \ @@ -283,7 +283,7 @@ return NULL; \ } -#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5) \ +#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5, ...) \ void *search_visitor_c::visit(class_name_c *symbol) { \ void *res = NULL; \ if (symbol->ref1) res = symbol->ref1->accept(*this); \ @@ -298,7 +298,7 @@ return NULL; \ } -#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \ +#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6, ...) \ void *search_visitor_c::visit(class_name_c *symbol) { \ void *res = NULL; \ if (symbol->ref1) res = symbol->ref1->accept(*this); \ diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax/visitor.hh --- a/absyntax/visitor.hh Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax/visitor.hh Fri Jul 29 16:03:28 2011 +0100 @@ -78,31 +78,31 @@ -#define SYM_LIST(class_name_c) \ - virtual void *visit(class_name_c *symbol) = 0; - -#define SYM_TOKEN(class_name_c) \ - virtual void *visit(class_name_c *symbol) = 0; - -#define SYM_REF0(class_name_c) \ - virtual void *visit(class_name_c *symbol) = 0; - -#define SYM_REF1(class_name_c, ref1) \ - virtual void *visit(class_name_c *symbol) = 0; - -#define SYM_REF2(class_name_c, ref1, ref2) \ - virtual void *visit(class_name_c *symbol) = 0; - -#define SYM_REF3(class_name_c, ref1, ref2, ref3) \ - virtual void *visit(class_name_c *symbol) = 0; - -#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \ - virtual void *visit(class_name_c *symbol) = 0; - -#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5) \ - virtual void *visit(class_name_c *symbol) = 0; - -#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \ +#define SYM_LIST(class_name_c, ...) \ + virtual void *visit(class_name_c *symbol) = 0; + +#define SYM_TOKEN(class_name_c, ...) \ + virtual void *visit(class_name_c *symbol) = 0; + +#define SYM_REF0(class_name_c, ...) \ + virtual void *visit(class_name_c *symbol) = 0; + +#define SYM_REF1(class_name_c, ref1, ...) \ + virtual void *visit(class_name_c *symbol) = 0; + +#define SYM_REF2(class_name_c, ref1, ref2, ...) \ + virtual void *visit(class_name_c *symbol) = 0; + +#define SYM_REF3(class_name_c, ref1, ref2, ref3, ...) \ + virtual void *visit(class_name_c *symbol) = 0; + +#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4, ...) \ + virtual void *visit(class_name_c *symbol) = 0; + +#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5, ...) \ + virtual void *visit(class_name_c *symbol) = 0; + +#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6, ...) \ virtual void *visit(class_name_c *symbol) = 0; class visitor_c { @@ -127,31 +127,31 @@ -#define SYM_LIST(class_name_c) \ - virtual void *visit(class_name_c *symbol); - -#define SYM_TOKEN(class_name_c) \ - virtual void *visit(class_name_c *symbol); - -#define SYM_REF0(class_name_c) \ - virtual void *visit(class_name_c *symbol); - -#define SYM_REF1(class_name_c, ref1) \ - virtual void *visit(class_name_c *symbol); - -#define SYM_REF2(class_name_c, ref1, ref2) \ - virtual void *visit(class_name_c *symbol); - -#define SYM_REF3(class_name_c, ref1, ref2, ref3) \ - virtual void *visit(class_name_c *symbol); - -#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \ - virtual void *visit(class_name_c *symbol); - -#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5) \ - virtual void *visit(class_name_c *symbol); - -#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \ +#define SYM_LIST(class_name_c, ...) \ + virtual void *visit(class_name_c *symbol); + +#define SYM_TOKEN(class_name_c, ...) \ + virtual void *visit(class_name_c *symbol); + +#define SYM_REF0(class_name_c, ...) \ + virtual void *visit(class_name_c *symbol); + +#define SYM_REF1(class_name_c, ref1, ...) \ + virtual void *visit(class_name_c *symbol); + +#define SYM_REF2(class_name_c, ref1, ref2, ...) \ + virtual void *visit(class_name_c *symbol); + +#define SYM_REF3(class_name_c, ref1, ref2, ref3, ...) \ + virtual void *visit(class_name_c *symbol); + +#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4, ...) \ + virtual void *visit(class_name_c *symbol); + +#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5, ...) \ + virtual void *visit(class_name_c *symbol); + +#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6, ...) \ virtual void *visit(class_name_c *symbol); diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax_utils/absyntax_utils.cc --- a/absyntax_utils/absyntax_utils.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax_utils/absyntax_utils.cc Fri Jul 29 16:03:28 2011 +0100 @@ -50,6 +50,7 @@ #include #include #include +#include /* required for atoi() */ #include "../util/symtable.hh" #include "../util/dsymtable.hh" @@ -94,6 +95,15 @@ } +/* extract the value of an integer from an integer_c object !! */ +/* NOTE: it must ignore underscores! */ +int extract_integer(symbol_c *sym) { + integer_c *integer = dynamic_cast(sym); + if (integer == NULL) ERROR; + + return atoi(integer->value); +} + /***********************************************************************/ /***********************************************************************/ diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax_utils/absyntax_utils.hh --- a/absyntax_utils/absyntax_utils.hh Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax_utils/absyntax_utils.hh Fri Jul 29 16:03:28 2011 +0100 @@ -55,9 +55,13 @@ /* returns 0 if the names are equal!! Case is ignored. */ int compare_identifiers(symbol_c *ident1, symbol_c *ident2); +/* extract the value of an integer from an integer_c object !! */ +int extract_integer(symbol_c *integer); + /* A symbol table with all globally declared functions... */ extern function_declaration_c null_symbol1; -extern dsymtable_c function_symtable; +typedef dsymtable_c function_symtable_t; +extern function_symtable_t function_symtable; /* A symbol table with all globally declared functions block types... */ extern function_block_declaration_c null_symbol2; diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax_utils/add_en_eno_param_decl.cc --- a/absyntax_utils/add_en_eno_param_decl.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax_utils/add_en_eno_param_decl.cc Fri Jul 29 16:03:28 2011 +0100 @@ -150,8 +150,17 @@ en_declared = false; eno_declared = false; iterate_list(symbol); + /* insert elements to begining of list! */ + /* We want EN first, and then ENO. + * But, since we are insertin them into the head of the list, we must insert EN last so it will stay in the first position! + */ + if(eno_declared == false) symbol->insert_element(build_eno_param()); + if(en_declared == false) symbol->insert_element(build_en_param()); + /* append elements to end of list! */ + /* if(en_declared == false) symbol->add_element(build_en_param()); if(eno_declared == false) symbol->add_element(build_eno_param()); + */ return NULL; } diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax_utils/function_call_param_iterator.cc --- a/absyntax_utils/function_call_param_iterator.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax_utils/function_call_param_iterator.cc Fri Jul 29 16:03:28 2011 +0100 @@ -221,6 +221,13 @@ return (symbol_c *)res; } +/* Search for the value passed to the parameter named ... */ +symbol_c *function_call_param_iterator_c::search_f(const char *param_name) { + identifier_c tmp_indentifier(param_name); + return search_f(&tmp_indentifier); +} + + /* Returns the value being passed to the current parameter. */ symbol_c *function_call_param_iterator_c::get_current_value(void) { return current_value; diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax_utils/function_call_param_iterator.hh --- a/absyntax_utils/function_call_param_iterator.hh Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax_utils/function_call_param_iterator.hh Fri Jul 29 16:03:28 2011 +0100 @@ -104,6 +104,7 @@ /* Search for the value passed to the parameter named ... */ symbol_c *search_f(symbol_c *param_name); + symbol_c *search_f(const char *param_name); /* Returns the value being passed to the current parameter. */ symbol_c *get_current_value(void); diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax_utils/function_param_iterator.cc --- a/absyntax_utils/function_param_iterator.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax_utils/function_param_iterator.cc Fri Jul 29 16:03:28 2011 +0100 @@ -48,8 +48,11 @@ -#include "function_param_iterator.hh" -#include "spec_init_separator.hh" +#include "absyntax_utils.hh" /* required for extract_integer() */ +// #include "function_param_iterator.hh" /* no longer required, aready included by absyntax_utils.hh */ +// #include "spec_init_separator.hh" /* no longer required, aready included by absyntax_utils.hh */ +#include /* required for strtol() */ +#include #include @@ -67,6 +70,49 @@ +/* compare the name of two __extensible__ function parameters. + * The usual use case is to have one of the parameters as used + * in the function declaration, and another as used in a formal function call. + * + * Will return: + * < 0 : if two parameters are not compatible, or one is invalid + * >= 0 : if both parameters .......... + */ +/* + * ("in", "i0") -> returns error (<0) + * ("in1", "in") -> returns error (<0) + * ("in", "in") -> returns error (<0) + * ("in", "inw") -> returns error (<0) + * ("in", "in10.4") -> returns error (<0) + * ("in", "in10e") -> returns error (<0) + * ("in", "") -> returns error (<0) + * ("", "in10e") -> returns error (<0) + * ("in", "in0") -> returns 0 + * ("in", "in9") -> returns 9 + * ("in", "in42") -> returns 42 + * ("in", "in-42") -> returns -42 (error!) + */ +int function_param_iterator_c::cmp_extparam_names(const char* s1, const char* s2) { + int res; + char *endptr; + int len; + + if ((s1 == NULL) || (s2 == NULL) || (*s1 == '\0') || (*s2 == '\0')) return -1; + + len = strlen(s1); + if (strncasecmp(s1, s2, len)) return -2; + + s1 = &s2[len]; + if (*s1 == '\0') return -3; + + res = strtol(s1, &endptr, 10); + if (*endptr != '\0') return -4; + + return res; +} + + + void* function_param_iterator_c::handle_param_list(list_c *list) { switch (current_operation) { case iterate_op: @@ -79,12 +125,27 @@ case search_op: for(int i = 0; i < list->n; i++) { - identifier_c *variable_name = dynamic_cast(list->elements[i]); + symbol_c *sym = list->elements[i]; + extensible_input_parameter_c *extensible_parameter = dynamic_cast(sym); + if (extensible_parameter != NULL) { + sym = extensible_parameter->var_name; + current_param_is_extensible = true; + _first_extensible_param_index = extract_integer(extensible_parameter->first_index); + } + identifier_c *variable_name = dynamic_cast(sym); if (variable_name == NULL) ERROR; - - if (strcasecmp(search_param_name->value, variable_name->value) == 0) - /* FOUND! This is the same parameter!! */ - return (void *)variable_name; + + if (!current_param_is_extensible) + if (strcasecmp(search_param_name->value, variable_name->value) == 0) + /* FOUND! This is the same parameter!! */ + return (void *)variable_name; + + if (current_param_is_extensible) { + current_extensible_param_index = cmp_extparam_names(variable_name->value, search_param_name->value); + if (current_extensible_param_index >= 0) + /* FOUND! This is a compatible extensible parameter!! */ + return (void *)variable_name; + } } break; } /* switch */ @@ -102,12 +163,26 @@ break; case search_op: + extensible_input_parameter_c *extensible_parameter = dynamic_cast(var_name); + if (extensible_parameter != NULL) { + var_name = extensible_parameter->var_name; + current_param_is_extensible = true; + _first_extensible_param_index = extract_integer(extensible_parameter->first_index); + } identifier_c *variable_name = dynamic_cast(var_name); if (variable_name == NULL) ERROR; - - if (strcasecmp(search_param_name->value, variable_name->value) == 0) - /* FOUND! This is the same parameter!! */ - return (void *)variable_name; + + if (!current_param_is_extensible) + if (strcasecmp(search_param_name->value, variable_name->value) == 0) + /* FOUND! This is the same parameter!! */ + return (void *)variable_name; + + if (current_param_is_extensible) { + current_extensible_param_index = cmp_extparam_names(variable_name->value, search_param_name->value); + if (current_extensible_param_index >= 0) + /* FOUND! This is a compatible extensible parameter!! */ + return (void *)variable_name; + } break; } /* switch */ @@ -128,6 +203,8 @@ /* start off at the first parameter once again... */ void function_param_iterator_c::reset(void) { next_param = param_count = 0; + _first_extensible_param_index = -1; + current_param_is_extensible = false; current_param_name = NULL; current_param_type = current_param_default_value = NULL; } @@ -166,6 +243,11 @@ void *res; identifier_c *identifier; + if (current_param_is_extensible) { + current_extensible_param_index++; + return current_param_name; + } + param_count = 0; en_eno_param_implicit = false; next_param++; @@ -175,6 +257,13 @@ return NULL; symbol_c *sym = (symbol_c *)res; + extensible_input_parameter_c *extensible_parameter = dynamic_cast(sym); + if (extensible_parameter != NULL) { + sym = extensible_parameter->var_name; + current_param_is_extensible = true; + _first_extensible_param_index = extract_integer(extensible_parameter->first_index); + current_extensible_param_index = _first_extensible_param_index; + } identifier = dynamic_cast(sym); if (identifier == NULL) ERROR; @@ -187,6 +276,8 @@ if (NULL == param_name) ERROR; search_param_name = dynamic_cast(param_name); if (NULL == search_param_name) ERROR; + en_eno_param_implicit = false; + current_param_is_extensible = false; current_operation = function_param_iterator_c::search_op; void *res = f_decl->accept(*this); identifier_c *res_param_name = dynamic_cast((symbol_c *)res); @@ -210,6 +301,24 @@ return en_eno_param_implicit; } +/* Returns if currently referenced parameter is an extensible parameter. */ +/* extensible paramters only occur in some standard functions, e.g. AND(word#34, word#44, word#65); */ +bool function_param_iterator_c::is_extensible_param(void) { + return current_param_is_extensible; +} + +/* Returns the index of the current extensible parameter. */ +/* If the current parameter is not an extensible paramter, returns -1 */ +int function_param_iterator_c::extensible_param_index(void) { + return (current_param_is_extensible? current_extensible_param_index : -1); +} + +/* Returns the index of the first extensible parameter, or -1 if no extensible parameter found. */ +/* WARNING: Will only return the correct value _after_ an extensible parameter has been found! */ +int function_param_iterator_c::first_extensible_param_index(void) { + return _first_extensible_param_index; +} + /* Returns the currently referenced parameter's data passing direction. * i.e. VAR_INPUT, VAR_OUTPUT or VAR_INOUT */ @@ -218,7 +327,7 @@ } void *function_param_iterator_c::visit(implicit_definition_c *symbol) { - en_eno_param_implicit = current_operation == function_param_iterator_c::iterate_op; + en_eno_param_implicit = true; return NULL; } @@ -243,12 +352,15 @@ * variables will get overwritten when we visit the next * var1_init_decl_c list! */ - symbol->method->accept(*this); - current_param_default_value = symbol->value; current_param_type = symbol->type; - return handle_single_param(symbol->name); + void *res = handle_single_param(symbol->name); + + /* If we have found the parameter we will be returning, we set the en_eno_param_implicit to TRUE if implicitly defined */ + if (res != NULL) symbol->method->accept(*this); + + return res; } /* var1_list ':' array_spec_init */ @@ -278,6 +390,7 @@ current_param_direction = direction_out; return symbol->var_init_decl_list->accept(*this); } + void *function_param_iterator_c::visit(eno_param_declaration_c *symbol) { TRACE("eno_param_declaration_c"); /* It is OK to store these values in the current_param_XXX @@ -286,18 +399,23 @@ * variables will get overwritten when we visit the next * var1_init_decl_c list! */ - symbol->method->accept(*this); - current_param_default_value = NULL; current_param_type = symbol->type; - return handle_single_param(symbol->name); -} + void *res = handle_single_param(symbol->name); + + /* If we have found the parameter we will be returning, we set the en_eno_param_implicit to TRUE if implicitly defined */ + if (res != NULL) symbol->method->accept(*this); + + return res; +} + void *function_param_iterator_c::visit(input_output_declarations_c *symbol) { TRACE("input_output_declarations_c"); current_param_direction = direction_inout; return symbol->var_declaration_list->accept(*this); } + void *function_param_iterator_c::visit(var_declaration_list_c *symbol) {TRACE("var_declaration_list_c"); return iterate_list(symbol);} /* var1_list ':' array_specification */ @@ -425,12 +543,12 @@ } - void *function_param_iterator_c::visit(var1_list_c *symbol) { TRACE("var1_list_c"); return handle_param_list(symbol); } + void *function_param_iterator_c::visit(var_init_decl_list_c *symbol) {TRACE("var_init_decl_list_c"); return iterate_list(symbol);} diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax_utils/function_param_iterator.hh --- a/absyntax_utils/function_param_iterator.hh Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax_utils/function_param_iterator.hh Fri Jul 29 16:03:28 2011 +0100 @@ -90,6 +90,16 @@ symbol_c *current_param_default_value; param_direction_t current_param_direction; bool en_eno_param_implicit; + /* used when we reach an extensible parameter in the function declaration */ + /* NOTE: this will handle syntax that is not in the standard. + * It is used to handle the extensible standard functions + * (e.g. AND(word#3, word#55, word#44); ) + * See absyntax.def or iec.y for more details. + */ + bool current_param_is_extensible; + int current_extensible_param_index; + int _first_extensible_param_index; + /* Which operation of the class was called... * Search a parameter, or iterate to the next parameter. */ @@ -97,6 +107,7 @@ operation_t current_operation; private: + int cmp_extparam_names(const char* s1, const char* s2); void* handle_param_list(list_c *list); void* handle_single_param(symbol_c *var_name); @@ -128,7 +139,8 @@ /* The seach() function does not in any way affect the internal state related * to the iterate() function. * It will, however, affect the internal state necessary to correctly - * return the param_type() and default_value() of the found parameter. + * return the param_type(), default_value() and is_en_eno_param_implicit() + * of the found parameter. */ identifier_c *search(symbol_c *param_name); @@ -143,6 +155,16 @@ /* Returns if currently referenced parameter is an implicit defined EN/ENO parameter. */ bool is_en_eno_param_implicit(void); + /* Returns if currently referenced parameter is an extensible parameter. */ + /* extensible paramters only occur in some standard functions, e.g. AND(word#34, word#44, word#65); */ + bool is_extensible_param(void); + /* Returns the index of the current extensible parameter. */ + /* If the current parameter is not an extensible paramter, returns -1 */ + int extensible_param_index(void); + /* Returns the index of the first extensible parameter, or -1 if no extensible parameter found. */ + /* WARNING: Will only return the correct value _after_ an extensible parameter has been found! */ + int first_extensible_param_index(void); + /* Returns the currently referenced parameter's data passing direction. * i.e. VAR_INPUT, VAR_OUTPUT or VAR_INOUT */ diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax_utils/search_expression_type.cc --- a/absyntax_utils/search_expression_type.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax_utils/search_expression_type.cc Fri Jul 29 16:03:28 2011 +0100 @@ -202,11 +202,6 @@ } -integer_c search_expression_type_c::integer("1"); // what default value should we use here ??? -#include "search_type_code.c" - -/*static bool_type_name_c bool_type_name;*/ - /* A helper function... */ void *search_expression_type_c::compute_boolean_expression(symbol_c *left_type, symbol_c *right_type) { if (!is_same_type(left_type, right_type)) @@ -385,13 +380,8 @@ } void *search_expression_type_c::visit(function_invocation_c *symbol) { - function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); - if (f_decl == function_symtable.end_value()) { - void *res = compute_standard_function_default(symbol); - if (res == NULL) - ERROR; - return res; - } + function_declaration_c *f_decl = (function_declaration_c *)symbol->called_function_declaration; + if (f_decl == NULL) ERROR; return base_type(f_decl->type_name); } diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax_utils/search_expression_type.hh --- a/absyntax_utils/search_expression_type.hh Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax_utils/search_expression_type.hh Fri Jul 29 16:03:28 2011 +0100 @@ -39,6 +39,18 @@ * etc... */ +/* WARNING WARNING WARNING + * + * When taking into consideration calls to functions, this search_expression_type_c + * class will use internal atributes (i.e. anotation) in the function_invocation_c symbol + * in the abstract syntax tree. + * + * Since this anotation/atribute is only set/populated with the correct value + * during stage3 (semantic verification), this class will only work correctly + * after the semantic verification in stage 3 has been executed + * (to be more exact, the data type checking of stage 3). + */ + class search_expression_type_c: public search_constant_type_c { private: diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax_utils/spec_init_separator.cc --- a/absyntax_utils/spec_init_separator.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax_utils/spec_init_separator.cc Fri Jul 29 16:03:28 2011 +0100 @@ -176,5 +176,35 @@ return NULL; } + +/* STRING '[' integer ']' + * STRING ASSIGN single_byte_character_string + * STRING '[' integer ']' ASSIGN single_byte_character_string + */ +void *spec_init_sperator_c::visit(single_byte_string_spec_c *symbol) { + TRACE("spec_init_sperator_c::single_byte_string_spec_c"); + switch (search_what) { + case search_spec: return symbol->string_spec; + case search_init: return symbol->single_byte_character_string; + } + ERROR; /* should never occur */ + return NULL; +} + +/* WSTRING '[' integer ']' + * WSTRING ASSIGN double_byte_character_string + * WSTRING '[' integer ']' ASSIGN double_byte_character_string + */ +void *spec_init_sperator_c::visit(double_byte_string_spec_c *symbol) { + TRACE("spec_init_sperator_c::double_byte_string_spec_c"); + switch (search_what) { + case search_spec: return symbol->string_spec; + case search_init: return symbol->double_byte_character_string; + } + ERROR; /* should never occur */ + return NULL; +} + + spec_init_sperator_c *spec_init_sperator_c ::class_instance = NULL; spec_init_sperator_c::search_what_t spec_init_sperator_c::search_what; diff -r ba80c3ceb6fb -r 2c3c4dc34979 absyntax_utils/spec_init_separator.hh --- a/absyntax_utils/spec_init_separator.hh Mon Jul 11 09:47:27 2011 +0100 +++ b/absyntax_utils/spec_init_separator.hh Fri Jul 29 16:03:28 2011 +0100 @@ -101,4 +101,17 @@ /* fb_name_list ':' function_block_type_name ASSIGN structure_initialization */ /* structure_initialization -> may be NULL ! */ void *visit(fb_name_decl_c *symbol); + + /* STRING '[' integer ']' + * STRING ASSIGN single_byte_character_string + * STRING '[' integer ']' ASSIGN single_byte_character_string + */ + void *visit(single_byte_string_spec_c *symbol); + + /* WSTRING '[' integer ']' + * WSTRING ASSIGN double_byte_character_string + * WSTRING '[' integer ']' ASSIGN double_byte_character_string + */ + void *visit(double_byte_string_spec_c *symbol); + }; /* class spec_init_sperator_c */ diff -r ba80c3ceb6fb -r 2c3c4dc34979 lib/iec_std_lib.h --- a/lib/iec_std_lib.h Mon Jul 11 09:47:27 2011 +0100 +++ b/lib/iec_std_lib.h Fri Jul 29 16:03:28 2011 +0100 @@ -1,5 +1,6 @@ /* - * (c) 2008 Edouard TISSERANT + * copyright 2008 Edouard TISSERANT + * copyright 2011 Mario de Sousa (msousa@fe.up.pt) * * Offered to the public under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either version 2 @@ -18,6 +19,13 @@ * IEC 61131-3 standard function library */ +/* NOTE: This file is full of (what may seem at first) very strange macros. + * If you want to know what all these strange macros are doing, + * just parse this file through a C preprocessor (e.g. cpp), + * and analyse the output! + * $gcc -E iec_std_lib.h + */ + #include #include #include @@ -51,7 +59,7 @@ u_int16_t body[STR_MAX_LEN]; } WSTRING; */ - +/* # if __WORDSIZE == 64 #define __32b_sufix #define __64b_sufix L @@ -59,6 +67,19 @@ #define __32b_sufix L #define __64b_sufix LL #endif +*/ + +# if __WORDSIZE == 64 +#define __32b_sufix +#define __64b_sufix L +#else +#define __32b_sufix L +/* changed this from LL to L temporarily. It was causing a bug when compiling resulting code with gcc. + * I have other things to worry about at the moment.. + */ +#define __64b_sufix L +#endif + #define __lit(type,value,sfx) (type)value##sfx // Keep this macro expention step to let sfx change into L or LL @@ -83,7 +104,7 @@ #define __BYTE_LITERAL(value) __literal(BYTE,value,) #define __WORD_LITERAL(value) __literal(WORD,value,) #define __DWORD_LITERAL(value) __literal(DWORD,value,__32b_sufix) -#define __LWORD_LITERAL(value) __literal(LWORD,value,__32b_sufix) +#define __LWORD_LITERAL(value) __literal(LWORD,value,__64b_sufix) @@ -136,17 +157,33 @@ DATE DATEvar; } __IL_DEFVAR_T; -/*****************/ -/* Misc internal */ -/*****************/ + +/**********************************************************************/ +/**********************************************************************/ +/***** *****/ +/***** Some helper functions... *****/ +/***** ...used later: *****/ +/***** - when declaring the IEC 61131-3 standard functions *****/ +/***** - in the C source code itself in SFC and ST expressions *****/ +/***** *****/ +/**********************************************************************/ +/**********************************************************************/ + + +/****************************/ +/* Notify IEC runtime error */ +/****************************/ /* function that generates an IEC runtime error */ -static inline void IEC_error(void) { +static inline void __iec_error(void) { /* TODO... */ fprintf(stderr, "IEC 61131-3 runtime error.\n"); /*exit(1);*/ } +/*******************************/ +/* Time normalization function */ +/*******************************/ static inline void __normalize_timespec (IEC_TIMESPEC *ts) { if( ts->tv_nsec < -1000000000 || (( ts->tv_sec > 0 ) && ( ts->tv_nsec < 0 ))){ @@ -159,6 +196,10 @@ } } +/**********************************************/ +/* Time conversion to/from timespec functions */ +/**********************************************/ + static inline IEC_TIMESPEC __time_to_timespec(int sign, double mseconds, double seconds, double minutes, double hours, double days) { IEC_TIMESPEC ts; @@ -197,7 +238,7 @@ epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */ if ((time_t)(-1) == epoch_seconds) - IEC_error(); + __iec_error(); ts.tv_sec = epoch_seconds; ts.tv_nsec = 0; @@ -223,56 +264,35 @@ epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */ if ((time_t)(-1) == epoch_seconds) - IEC_error(); + __iec_error(); ts.tv_sec += epoch_seconds; if (ts.tv_sec < epoch_seconds) /* since the TOD is always positive, if the above happens then we had an overflow */ - IEC_error(); + __iec_error(); return ts; } -/********************/ -/* EN/ENO PARAMS */ -/********************/ - -#define EN_ENO_PARAMS BOOL EN, BOOL *ENO -#define TEST_EN(TYPENAME)\ - if (!EN) {\ - if (ENO != NULL)\ - *ENO = __BOOL_LITERAL(FALSE);\ - return __INIT_##TYPENAME;\ - }\ - else if (ENO != NULL)\ - *ENO = __BOOL_LITERAL(TRUE); -#define TEST_EN_COND(TYPENAME, COND)\ - if (!EN || (COND)) {\ - if (ENO != NULL)\ - *ENO = __BOOL_LITERAL(FALSE);\ - return __INIT_##TYPENAME;\ - }\ - else if (ENO != NULL)\ - *ENO = __BOOL_LITERAL(TRUE); - -/***************/ -/* Time ops */ -/***************/ -#define __TIME_CMP(t1, t2) (t2.tv_sec == t1.tv_sec ? t1.tv_nsec - t2.tv_nsec : t1.tv_sec - t2.tv_sec) - -static inline TIME __TIME_ADD(TIME IN1, TIME IN2){ +/*******************/ +/* Time operations */ +/*******************/ + +#define __time_cmp(t1, t2) (t2.tv_sec == t1.tv_sec ? t1.tv_nsec - t2.tv_nsec : t1.tv_sec - t2.tv_sec) + +static inline TIME __time_add(TIME IN1, TIME IN2){ TIME res ={IN1.tv_sec + IN2.tv_sec, IN1.tv_nsec + IN2.tv_nsec }; __normalize_timespec(&res); return res; } -static inline TIME __TIME_SUB(TIME IN1, TIME IN2){ +static inline TIME __time_sub(TIME IN1, TIME IN2){ TIME res ={IN1.tv_sec - IN2.tv_sec, IN1.tv_nsec - IN2.tv_nsec }; __normalize_timespec(&res); return res; } -static inline TIME __TIME_MUL(TIME IN1, LREAL IN2){ +static inline TIME __time_mul(TIME IN1, LREAL IN2){ LREAL s_f = IN1.tv_sec * IN2; time_t s = s_f; div_t ns = div((LREAL)IN1.tv_nsec * IN2, 1000000000); @@ -281,7 +301,7 @@ __normalize_timespec(&res); return res; } -static inline TIME __TIME_DIV(TIME IN1, LREAL IN2){ +static inline TIME __time_div(TIME IN1, LREAL IN2){ LREAL s_f = IN1.tv_sec / IN2; time_t s = s_f; TIME res = {s, @@ -290,183 +310,6 @@ return res; } -static inline TIME __date_and_time_to_time_of_day(EN_ENO_PARAMS, TIME IN){ - TEST_EN(TIME) - return (TIME){IN.tv_sec % 86400, IN.tv_nsec}; -} -static inline TIME __date_and_time_to_date(EN_ENO_PARAMS, TIME IN){ - TEST_EN(TIME) - return (TIME){IN.tv_sec - (IN.tv_sec % (24*60*60)), 0}; -} -static inline TIME __time_add(EN_ENO_PARAMS, TIME IN1, TIME IN2){ - TEST_EN(TIME) - return __TIME_ADD(IN1, IN2); -} -static inline TIME __time_sub(EN_ENO_PARAMS, TIME IN1, TIME IN2){ - TEST_EN(TIME) - return __TIME_SUB(IN1, IN2); -} -static inline TIME __time_mul(EN_ENO_PARAMS, TIME IN1, LREAL IN2){ - TEST_EN(TIME) - return __TIME_MUL(IN1, IN2); -} -static inline TIME __time_div(EN_ENO_PARAMS, TIME IN1, LREAL IN2){ - TEST_EN(TIME) - return __TIME_DIV(IN1, IN2); -} - -/***************/ -/* String ops */ -/***************/ -#define __STR_CMP(str1, str2) memcmp((char*)&str1.body,(char*)&str2.body, str1.len < str2.len ? str1.len : str2.len) - -static inline __strlen_t __len(EN_ENO_PARAMS, STRING IN){ - TEST_EN(UINT) - return IN.len; -} -static inline STRING __left(EN_ENO_PARAMS, STRING IN, __strlen_t L){ - STRING res; - TEST_EN_COND(STRING, L < 0) - res = __INIT_STRING; - L = L < IN.len ? L : IN.len; - memcpy(&res.body, &IN.body, L); - res.len = L; - return res; -} -static inline STRING __right(EN_ENO_PARAMS, STRING IN, __strlen_t L){ - STRING res; - TEST_EN_COND(STRING, L < 0) - res = __INIT_STRING; - L = L < IN.len ? L : IN.len; - memcpy(&res.body, &IN.body[IN.len - L], L); - res.len = L; - return res; -} -static inline STRING __mid(EN_ENO_PARAMS, STRING IN, __strlen_t L, __strlen_t P){ - STRING res; - TEST_EN_COND(STRING, L < 0 || P < 0) - res = __INIT_STRING; - if(P <= IN.len){ - P -= 1; /* now can be used as [index]*/ - L = L + P <= IN.len ? L : IN.len - P; - memcpy(&res.body, &IN.body[P] , L); - res.len = L; - } - return res; -} -static inline STRING __concat(EN_ENO_PARAMS, UINT param_count, ...){ - UINT i; - STRING res; - va_list ap; - __strlen_t charcount; - TEST_EN(STRING) - charcount = 0; - res = __INIT_STRING; - - va_start (ap, param_count); /* Initialize the argument list. */ - - for (i = 0; i < param_count && charcount < STR_MAX_LEN; i++) - { - STRING tmp = va_arg(ap, STRING); - __strlen_t charrem = STR_MAX_LEN - charcount; - __strlen_t to_write = tmp.len > charrem ? charrem : tmp.len; - memcpy(&res.body[charcount], &tmp.body , to_write); - charcount += to_write; - } - - res.len = charcount; - - va_end (ap); /* Clean up. */ - return res; -} -static inline STRING __insert(EN_ENO_PARAMS, STRING IN1, STRING IN2, __strlen_t P){ - STRING res; - __strlen_t to_copy; - TEST_EN_COND(STRING, P < 0) - res = __INIT_STRING; - - to_copy = P > IN1.len ? IN1.len : P; - memcpy(&res.body, &IN1.body , to_copy); - P = res.len = to_copy; - - to_copy = IN2.len + res.len > STR_MAX_LEN ? STR_MAX_LEN - res.len : IN2.len; - memcpy(&res.body[res.len], &IN2.body , to_copy); - res.len += to_copy; - - to_copy = IN1.len - P < STR_MAX_LEN - res.len ? IN1.len - P : STR_MAX_LEN - res.len ; - memcpy(&res.body[res.len], &IN1.body[P] , to_copy); - res.len += to_copy; - - return res; -} -static inline STRING __delete(EN_ENO_PARAMS, STRING IN, __strlen_t L, __strlen_t P){ - STRING res; - __strlen_t to_copy; - TEST_EN_COND(STRING, L < 0 || P < 0) - res = __INIT_STRING; - - to_copy = P > IN.len ? IN.len : P-1; - memcpy(&res.body, &IN.body , to_copy); - P = res.len = to_copy; - - if( IN.len > P + L ){ - to_copy = IN.len - P - L; - memcpy(&res.body[res.len], &IN.body[P + L], to_copy); - res.len += to_copy; - } - - return res; -} -static inline STRING __replace(EN_ENO_PARAMS, STRING IN1, STRING IN2, __strlen_t L, __strlen_t P){ - STRING res; - __strlen_t to_copy; - TEST_EN_COND(STRING, L < 0 || P < 0) - res = __INIT_STRING; - - to_copy = P > IN1.len ? IN1.len : P-1; - memcpy(&res.body, &IN1.body , to_copy); - P = res.len = to_copy; - - to_copy = IN2.len < L ? IN2.len : L; - - if( to_copy + res.len > STR_MAX_LEN ) - to_copy = STR_MAX_LEN - res.len; - - memcpy(&res.body[res.len], &IN2.body , to_copy); - res.len += to_copy; - - P += L; - if( res.len < STR_MAX_LEN && P < IN1.len) - { - to_copy = IN1.len - P; - memcpy(&res.body[res.len], &IN1.body[P] , to_copy); - res.len += to_copy; - } - - return res; -} - - - -static inline __strlen_t __pfind(STRING* IN1, STRING* IN2){ - UINT count1 = 0; /* offset of first matching char in IN1 */ - UINT count2 = 0; /* count of matching char */ - while(count1 + count2 < IN1->len && count2 < IN2->len) - { - if(IN1->body[count1 + count2] != IN2->body[count2]){ - count1 += count2 + 1; - count2 = 0; - } - else { - count2++; - } - } - return count2 == IN2->len -1 ? 0 : count1 + 1; -} -static inline __strlen_t __find(EN_ENO_PARAMS, STRING IN1, STRING IN2){ - TEST_EN(UINT) - return __pfind(&IN1, &IN2); -} /***************/ /* Convertions */ @@ -474,67 +317,49 @@ /*****************/ /* REAL_TO_INT */ /*****************/ -static inline LINT __real_round(LREAL IN) -{ +static inline LINT __real_round(LREAL IN) { return fmod(IN, 1) == 0 ? ((LINT)IN / 2) * 2 : (LINT)IN; } -static inline LINT __preal_to_sint(LREAL IN) -{ +static inline LINT __preal_to_sint(LREAL IN) { return IN >= 0 ? __real_round(IN + 0.5) : __real_round(IN - 0.5); } -static inline LINT __preal_to_uint(LREAL IN) -{ +static inline LINT __preal_to_uint(LREAL IN) { return IN >= 0 ? __real_round(IN + 0.5) : 0; } -static inline LINT __real_to_sint(EN_ENO_PARAMS, LREAL IN){ - TEST_EN(LINT) - return (LINT)__preal_to_sint(IN); -} -static inline LWORD __real_to_bit(EN_ENO_PARAMS, LREAL IN){ - TEST_EN(LWORD) - return (LWORD)__preal_to_uint(IN); -} -static inline ULINT __real_to_uint(EN_ENO_PARAMS, LREAL IN){ - TEST_EN(ULINT) - return (ULINT)__preal_to_uint(IN); -} +static inline LINT __real_to_sint(LREAL IN) {return (LINT)__preal_to_sint(IN);} +static inline LWORD __real_to_bit(LREAL IN) {return (LWORD)__preal_to_uint(IN);} +static inline ULINT __real_to_uint(LREAL IN) {return (ULINT)__preal_to_uint(IN);} + /***************/ /* TO_STRING */ /***************/ -static inline STRING __bool_to_string(EN_ENO_PARAMS, BOOL IN) -{ - TEST_EN(STRING) - if(IN) - return (STRING){4, "TRUE"}; +static inline STRING __bool_to_string(BOOL IN) { + if(IN) return (STRING){4, "TRUE"}; return (STRING){5,"FALSE"}; } -static inline STRING __bit_to_string(EN_ENO_PARAMS, LWORD IN){ +static inline STRING __bit_to_string(LWORD IN) { STRING res; - TEST_EN(STRING) res = __INIT_STRING; res.len = snprintf((char*)res.body, STR_MAX_LEN, "16#%llx", IN); if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; return res; } -static inline STRING __real_to_string(EN_ENO_PARAMS, LREAL IN){ +static inline STRING __real_to_string(LREAL IN) { STRING res; - TEST_EN(STRING) res = __INIT_STRING; res.len = snprintf((char*)res.body, STR_MAX_LEN, "%.10g", IN); if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; return res; } -static inline STRING __sint_to_string(EN_ENO_PARAMS, LINT IN){ +static inline STRING __sint_to_string(LINT IN) { STRING res; - TEST_EN(STRING) res = __INIT_STRING; res.len = snprintf((char*)res.body, STR_MAX_LEN, "%lld", IN); if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; return res; } -static inline STRING __uint_to_string(EN_ENO_PARAMS, ULINT IN){ +static inline STRING __uint_to_string(ULINT IN) { STRING res; - TEST_EN(STRING) res = __INIT_STRING; res.len = snprintf((char*)res.body, STR_MAX_LEN, "%llu", IN); if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; @@ -543,12 +368,11 @@ /***************/ /* FROM_STRING */ /***************/ -static inline BOOL __string_to_bool(EN_ENO_PARAMS, STRING IN){ - TEST_EN(BOOL) +static inline BOOL __string_to_bool(STRING IN) { return IN.len == 5 ? !memcmp(&IN.body,"TRUE", IN.len) : 0; } -static inline LINT __pstring_to_sint(STRING* IN){ +static inline LINT __pstring_to_sint(STRING* IN) { LINT res = 0; __strlen_t l; unsigned int shift = 0; @@ -609,22 +433,12 @@ return res; } -static inline LINT __string_to_sint(EN_ENO_PARAMS, STRING IN){ - TEST_EN(LINT) - return (LINT)__pstring_to_sint(&IN); -} -static inline LWORD __string_to_bit(EN_ENO_PARAMS, STRING IN){ - TEST_EN(LWORD) - return (LWORD)__pstring_to_sint(&IN); -} -static inline ULINT __string_to_uint(EN_ENO_PARAMS, STRING IN){ - TEST_EN(ULINT) - return (ULINT)__pstring_to_sint(&IN); -} -static inline LREAL __string_to_real(EN_ENO_PARAMS, STRING IN){ - __strlen_t l; - TEST_EN(LREAL) - l = IN.len; +static inline LINT __string_to_sint(STRING IN) {return (LINT)__pstring_to_sint(&IN);} +static inline LWORD __string_to_bit (STRING IN) {return (LWORD)__pstring_to_sint(&IN);} +static inline ULINT __string_to_uint(STRING IN) {return (ULINT)__pstring_to_sint(&IN);} +static inline LREAL __string_to_real(STRING IN) { + __strlen_t l; + l = IN.len; /* search the dot */ while(--l > 0 && IN.body[l] != '.'); if(l != 0){ @@ -637,18 +451,10 @@ /***************/ /* TO_TIME */ /***************/ -static inline TIME __int_to_time(EN_ENO_PARAMS, LINT IN){ - TEST_EN(TIME) - return (TIME){IN, 0}; -} - -static inline TIME __real_to_time(EN_ENO_PARAMS, LREAL IN){ - TEST_EN(TIME) - return (TIME){IN, (IN - (LINT)IN) * 1000000000}; -} -static inline TIME __string_to_time(EN_ENO_PARAMS, STRING IN){ - __strlen_t l; - TEST_EN(TIME) +static inline TIME __int_to_time(LINT IN) {return (TIME){IN, 0};} +static inline TIME __real_to_time(LREAL IN) {return (TIME){IN, (IN - (LINT)IN) * 1000000000};} +static inline TIME __string_to_time(STRING IN){ + __strlen_t l; /* TODO : * * Duration literals without underlines: T#14ms T#-14ms T#14.7s T#14.7m @@ -671,7 +477,7 @@ */ /* Quick hack : only transform seconds */ /* search the dot */ - l = IN.len; + l = IN.len; while(--l > 0 && IN.body[l] != '.'); if(l != 0){ LREAL IN_val = atof((const char *)&IN.body); @@ -684,18 +490,13 @@ /***************/ /* FROM_TIME */ /***************/ -static inline LREAL __time_to_real(EN_ENO_PARAMS, TIME IN){ - TEST_EN(LREAL) +static inline LREAL __time_to_real(TIME IN){ return (LREAL)IN.tv_sec + ((LREAL)IN.tv_nsec/1000000000); } -static inline LINT __time_to_int(EN_ENO_PARAMS, TIME IN){ - TEST_EN(LINT) - return IN.tv_sec; -} -static inline STRING __time_to_string(EN_ENO_PARAMS, TIME IN){ +static inline LINT __time_to_int(TIME IN) {return IN.tv_sec;} +static inline STRING __time_to_string(TIME IN){ STRING res; div_t days; - TEST_EN(STRING) /*t#5d14h12m18s3.5ms*/ res = __INIT_STRING; days = div(IN.tv_sec ,86400); @@ -721,32 +522,30 @@ if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; return res; } -static inline STRING __date_to_string(EN_ENO_PARAMS, DATE IN){ +static inline STRING __date_to_string(DATE IN){ STRING res; struct tm* broken_down_time; time_t seconds; - TEST_EN(STRING) /* D#1984-06-25 */ res = __INIT_STRING; seconds = IN.tv_sec; if (NULL == (broken_down_time = localtime(&seconds))){ /* get the UTC (GMT) broken down time */ - IEC_error(); + __iec_error(); return (STRING){7,"D#ERROR"}; } res.len = snprintf((char*)&res.body, STR_MAX_LEN, "D#%d-%2.2d-%2.2d", broken_down_time->tm_year + 1900, broken_down_time->tm_mon + 1, broken_down_time->tm_mday); if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; return res; } -static inline STRING __tod_to_string(EN_ENO_PARAMS, TOD IN){ +static inline STRING __tod_to_string(TOD IN){ STRING res; struct tm* broken_down_time; time_t seconds; - TEST_EN(STRING) /* TOD#15:36:55.36 */ res = __INIT_STRING; seconds = IN.tv_sec; if (NULL == (broken_down_time = localtime(&seconds))){ /* get the UTC (GMT) broken down time */ - IEC_error(); + __iec_error(); return (STRING){9,"TOD#ERROR"}; } if(IN.tv_nsec == 0){ @@ -757,15 +556,14 @@ if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; return res; } -static inline STRING __dt_to_string(EN_ENO_PARAMS, DT IN){ +static inline STRING __dt_to_string(DT IN){ STRING res; struct tm* broken_down_time; time_t seconds; - TEST_EN(STRING) /* DT#1984-06-25-15:36:55.36 */ seconds = IN.tv_sec; if (NULL == (broken_down_time = localtime(&seconds))){ /* get the UTC (GMT) broken down time */ - IEC_error(); + __iec_error(); return (STRING){8,"DT#ERROR"}; } if(IN.tv_nsec == 0){ @@ -788,12 +586,21 @@ if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; return res; } - /* BCD */ + + /**********************************************/ + /* [ANY_DATE | TIME] _TO_ [ANY_DATE | TIME] */ + /**********************************************/ + +static inline TOD __date_and_time_to_time_of_day(DT IN) {return (TOD){IN.tv_sec % 86400, IN.tv_nsec};} +static inline DATE __date_and_time_to_date(DT IN){return (DATE){IN.tv_sec - (IN.tv_sec % (24*60*60)), 0};} + + /*****************/ + /* FROM/TO BCD */ + /*****************/ #define __bcd_digit(fac) -static inline ULINT __bcd_to_uint(EN_ENO_PARAMS, LWORD IN){ +static inline ULINT __bcd_to_uint(LWORD IN){ ULINT res; ULINT i; - TEST_EN(ULINT) res = IN & 0xf; for(i = 10ULL; i <= 1000000000000000ULL; i *= 10){ @@ -804,10 +611,9 @@ return res; } -static inline LWORD __uint_to_bcd(EN_ENO_PARAMS, ULINT IN){ +static inline LWORD __uint_to_bcd(ULINT IN){ LWORD res; USINT i; - TEST_EN(LWORD) res = IN % 10; for(i = 4; i<=60; i += 4){ @@ -818,6 +624,296 @@ return res; } + + /************/ + /* MOVE_* */ + /************/ + +/* some helpful __move_[ANY] functions, used in the *_TO_** and MOVE standard functions */ +/* e.g. __move_BOOL, __move_BYTE, __move_REAL, __move_TIME, ... */ +#define __iec_(TYPENAME)\ +static inline TYPENAME __move_##TYPENAME(TYPENAME op1) {return op1;} +__ANY(__iec_) +#undef __iec_ + + + +/*****************************************************************/ +/*****************************************************************/ +/***** *****/ +/***** IEC 61131-3 *****/ +/***** S T A N D A R D F U N C T I O N S *****/ +/***** *****/ +/*****************************************************************/ +/*****************************************************************/ + +/* NOTE: If you want to know what all these strange macros are doing, + * just parse this file through a C preprocessor, and analyse the output! + * $gcc -E iec_std_lib.h + */ + +/* NOTE: We only define and declare the explicitly typed standard functions + * (e.g., SIN_REAL, SIN_LREAL, ..., ADD_SINT, ADD_INT, ADD_LINT, ...) + * We do not declare/define the overloaded functions + * (SIN, ADD, ...). + * When handling a call to an overloaded function, the iec2c compiler + * will determine in stage3 the data type of the parameter being passed, + * and in stage4 generate the C code to call the correct + * typed standard function. + */ + +/* NOTE on explicit typing of: + * - Table 25 - Standard bit shift functions + * - Table 29 - Character string Functions + * + * In section 2.5.1.4 (Typing, overloading, and type conversion) of the IEC 61131-3 (version 2) + * of the standard, it is stated: + * "A standard function, [...] is said to be overloaded when it + * can operate on input data elements of various types within a generic type designator as defined in + * 2.3.2. For instance, an overloaded addition function on generic type ANY_NUM can operate on data + * of types LREAL, REAL, DINT, INT, and SINT." + * [...] + * "When a function which normally represents an overloaded operator is to be typed, i.e., the types + * of its inputs and outputs restricted to a particular elementary or derived data type as defined in + * 2.3, this shall be done by appending an "underline" character followed by the required type, as + * shown in table 21." + * + * However, this explanation (as well as the example in table 21) only refers to functions where the same + * generic data type is used for the single input and the output parameter. + * How can we create explicitly types functions when this is not the case? + * It does not seem to be covered by the standard. + * + * For this reason, we do not define the LEN_SINT, LEN_INT, LEN_STRING, LEN_[ANY_INT], LEN_[ANY_STRING] functions... + */ + + +/********************/ +/* EN/ENO PARAMS */ +/********************/ + +#define EN_ENO_PARAMS BOOL EN, BOOL *ENO + +#define TEST_EN(TYPENAME)\ + if (!EN) {\ + if (ENO != NULL)\ + *ENO = __BOOL_LITERAL(FALSE);\ + return __INIT_##TYPENAME;\ + }\ + else if (ENO != NULL)\ + *ENO = __BOOL_LITERAL(TRUE); + +#define TEST_EN_COND(TYPENAME, COND)\ + if (!EN || (COND)) {\ + if (ENO != NULL)\ + *ENO = __BOOL_LITERAL(FALSE);\ + return __INIT_##TYPENAME;\ + }\ + else if (ENO != NULL)\ + *ENO = __BOOL_LITERAL(TRUE); + + + +/*****************************************/ +/*****************************************/ +/* 2.5.1.5.1 Type Conversion Functions */ +/*****************************************/ +/*****************************************/ + +#define __convert_type(from_TYPENAME,to_TYPENAME, oper) \ +static inline to_TYPENAME from_TYPENAME##_TO_##to_TYPENAME(EN_ENO_PARAMS, from_TYPENAME op){\ + TEST_EN(to_TYPENAME)\ + return (to_TYPENAME)oper(op);\ +} + + +#define __to_anynum_(from_TYPENAME) __ANY_NUM_1(__iec_,from_TYPENAME) +#define __to_anyint_(from_TYPENAME) __ANY_INT_1(__iec_,from_TYPENAME) +#define __to_anybit_(from_TYPENAME) __ANY_BIT_1(__iec_,from_TYPENAME) +#define __to_anynbit_(from_TYPENAME) __ANY_NBIT_1(__iec_,from_TYPENAME) +#define __to_anysint_(from_TYPENAME) __ANY_SINT_1(__iec_,from_TYPENAME) +#define __to_anyuint_(from_TYPENAME) __ANY_UINT_1(__iec_,from_TYPENAME) +#define __to_anyreal_(from_TYPENAME) __ANY_REAL_1(__iec_,from_TYPENAME) +#define __to_anydate_(from_TYPENAME) __ANY_DATE_1(__iec_,from_TYPENAME) + +/******** [ANY_BIT]_TO_[ANY_NUM | ANT_BIT] ************/ +#define __iec_(to_TYPENAME,from_TYPENAME) __convert_type(from_TYPENAME, to_TYPENAME, __move_##to_TYPENAME) +__ANY_BIT(__to_anynum_) +__ANY_BIT(__to_anybit_) +#undef __iec_ + +/******** [ANY_INT]_TO_[ANY_NUM | ANT_BIT] ************/ +#define __iec_(to_TYPENAME,from_TYPENAME) __convert_type(from_TYPENAME, to_TYPENAME, __move_##to_TYPENAME) +__ANY_INT(__to_anynum_) +__ANY_INT(__to_anybit_) +#undef __iec_ + +/******** [ANY_REAL]_TO_[ANY_BIT] ************/ +#define __iec_(to_TYPENAME,from_TYPENAME) __convert_type(from_TYPENAME, to_TYPENAME, __real_to_bit) +__ANY_REAL(__to_anybit_) +#undef __iec_ + +/******** [ANY_REAL]_TO_[ANY_INT] ************/ +#define __iec_(to_TYPENAME,from_TYPENAME) __convert_type(from_TYPENAME, to_TYPENAME, __real_to_sint) +__ANY_REAL(__to_anysint_) +#undef __iec_ +#define __iec_(to_TYPENAME,from_TYPENAME) __convert_type(from_TYPENAME, to_TYPENAME, __real_to_uint) +__ANY_REAL(__to_anyuint_) +#undef __iec_ + +/******** [ANY_REAL]_TO_[ANY_REAL] ************/ +#define __iec_(to_TYPENAME,from_TYPENAME) __convert_type(from_TYPENAME, to_TYPENAME, __move_##to_TYPENAME) +__ANY_REAL(__to_anyreal_) +#undef __iec_ + +/******** [ANY_BIT | ANY_INT]_TO_[TIME | ANY_DATE] ************/ +#define __iec_(from_TYPENAME) __convert_type(from_TYPENAME, TIME, __int_to_time) +__ANY_BIT(__iec_) +__ANY_INT(__iec_) +#undef __iec_ +#define __iec_(to_TYPENAME,from_TYPENAME) __convert_type(from_TYPENAME, to_TYPENAME, __int_to_time) +__ANY_BIT(__to_anydate_) +__ANY_INT(__to_anydate_) +#undef __iec_ + +/******** [ANY_REAL]_TO_[TIME | ANY_DATE] ************/ +#define __iec_(from_TYPENAME) __convert_type(from_TYPENAME, TIME, __real_to_time) +__ANY_REAL(__iec_) +#undef __iec_ +#define __iec_(to_TYPENAME,from_TYPENAME) __convert_type(from_TYPENAME, to_TYPENAME, __real_to_time) +__ANY_REAL(__to_anydate_) +#undef __iec_ + +/******** [TIME | ANY_DATE]_TO_[ANY_BIT | ANY_INT] ************/ +#define __iec_(to_TYPENAME,from_TYPENAME) __convert_type(from_TYPENAME, to_TYPENAME, __time_to_int) +__to_anyint_(TIME) +__to_anybit_(TIME) +__ANY_DATE(__to_anyint_) +__ANY_DATE(__to_anybit_) +#undef __iec_ + +/******** [TIME | ANY_DATE]_TO_[ANY_REAL] ************/ +#define __iec_(to_TYPENAME,from_TYPENAME) __convert_type(from_TYPENAME, to_TYPENAME, __time_to_real) +__to_anyreal_(TIME) +__ANY_DATE(__to_anyreal_) +#undef __iec_ + + +/******** [ANY_DATE]_TO_[ANY_DATE | TIME] ************/ +/* Not supported: DT_TO_TIME */ +__convert_type(DT, DATE, __date_and_time_to_date) +__convert_type(DT, DT, __move_DT) +__convert_type(DT, TOD, __date_and_time_to_time_of_day) +/* Not supported: DATE_TO_TIME */ +__convert_type(DATE, DATE, __move_DATE) +/* Not supported: DATE_TO_DT */ +/* Not supported: DATE_TO_TOD */ +/* Not supported: TOD_TO_TIME */ +/* Not supported: TOD_TO_DATE */ +/* Not supported: TOD_TO_DT */ +__convert_type(TOD, TOD, __move_TOD) + + +/******** TIME_TO_[ANY_DATE] ************/ +/* Not supported: TIME_TO_DATE */ +/* Not supported: TIME_TO_DT */ +/* Not supported: TIME_TO_TOD */ + +/******** TIME_TO_TIME ************/ +__convert_type(TIME, TIME, __move_TIME) + + +/******** [ANY_BIT]_TO_STRING ************/ +__convert_type(BOOL, STRING, __bool_to_string) +#define __iec_(from_TYPENAME) __convert_type(from_TYPENAME, STRING, __bit_to_string) +__ANY_NBIT(__iec_) +#undef __iec_ + +/******** [ANY_INT]_TO_STRING ************/ +#define __iec_(from_TYPENAME) __convert_type(from_TYPENAME, STRING, __sint_to_string) +__ANY_SINT(__iec_) +#undef __iec_ +#define __iec_(from_TYPENAME) __convert_type(from_TYPENAME, STRING, __uint_to_string) +__ANY_UINT(__iec_) +#undef __iec_ + +/******** [ANY_REAL]_TO_STRING ************/ +#define __iec_(from_TYPENAME) __convert_type(from_TYPENAME, STRING, __real_to_string) +__ANY_REAL(__iec_) +#undef __iec_ + +/******** [ANY_DATE]_TO_STRING ************/ +__convert_type(DATE, STRING, __date_to_string) +__convert_type(DT, STRING, __dt_to_string) +__convert_type(TOD, STRING, __tod_to_string) + +/******** TIME_TO_STRING ************/ +__convert_type(TIME, STRING, __time_to_string) + + +/******** STRING_TO_[ANY_BIT] ************/ +__convert_type(STRING, BOOL, __string_to_bool) +#define __iec_(to_TYPENAME) __convert_type(STRING, to_TYPENAME, __string_to_bit) +__ANY_NBIT(__iec_) +#undef __iec_ + +/******** STRING_TO_[ANY_INT] ************/ +#define __iec_(to_TYPENAME) __convert_type(STRING, to_TYPENAME, __string_to_sint) +__ANY_SINT(__iec_) +#undef __iec_ +#define __iec_(to_TYPENAME) __convert_type(STRING, to_TYPENAME, __string_to_uint) +__ANY_UINT(__iec_) +#undef __iec_ + +/******** STRING_TO_[ANY_REAL] ************/ +#define __iec_(to_TYPENAME) __convert_type(STRING, to_TYPENAME, __string_to_real) +__ANY_REAL(__iec_) +#undef __iec_ + +/******** STRING_TO_[ANY_DATE] ************/ +#define __iec_(to_TYPENAME) __convert_type(STRING, to_TYPENAME, __string_to_time) +__ANY_DATE(__iec_) +#undef __iec_ + +/******** STRING_TO_TIME ************/ +__convert_type(STRING, TIME, __string_to_time) + + +/******** TRUNC ************/ +#define __iec_(to_TYPENAME,from_TYPENAME) \ +static inline to_TYPENAME TRUNC__##to_TYPENAME##__##from_TYPENAME(EN_ENO_PARAMS, from_TYPENAME op){\ + TEST_EN(to_TYPENAME)\ + return (to_TYPENAME)__move_##to_TYPENAME(op);\ +} +__ANY_REAL(__to_anyint_) +#undef __iec_ + + +/******** _TO_BCD ************/ +#define __iec_(to_TYPENAME,from_TYPENAME) \ +static inline to_TYPENAME from_TYPENAME##_TO_BCD_##to_TYPENAME(EN_ENO_PARAMS, from_TYPENAME op){\ + TEST_EN(to_TYPENAME)\ + return (to_TYPENAME)__uint_to_bcd(op);\ +} +__ANY_UINT(__to_anynbit_) +#undef __iec_ + + +/******** BCD_TO_ ************/ +#define __iec_(to_TYPENAME,from_TYPENAME) \ +static inline to_TYPENAME from_TYPENAME##_BCD_TO_##to_TYPENAME(EN_ENO_PARAMS, from_TYPENAME op){\ + TEST_EN(to_TYPENAME)\ + return (to_TYPENAME)__bcd_to_uint(op);\ +} +__ANY_NBIT(__to_anyuint_) +#undef __iec_ + + +/***********************************/ +/***********************************/ +/* 2.5.1.5.2 Numerical Functions */ +/***********************************/ +/***********************************/ + /* workaround for va-args limitation on shorter than int params */ #define VA_ARGS_REAL LREAL #define VA_ARGS_LREAL LREAL @@ -841,11 +937,187 @@ #define VA_ARGS_TOD TOD #define VA_ARGS_DT DT -/*******************************************/ -/* Arithmetic and bitwise functions */ -/*******************************************/ + +#define __numeric(fname,TYPENAME, FUNC) \ +static inline TYPENAME fname##TYPENAME(EN_ENO_PARAMS, TYPENAME op){\ + TEST_EN(TYPENAME)\ + return FUNC(op);\ +} + +/******************************************************************/ +/*** Table 23 - Standard functions of one numeric variable ***/ +/******************************************************************/ + + /**************/ + /* ABS */ + /**************/ +/* explicitly typed function */ +#define __iec_(TYPENAME) \ +static inline TYPENAME ABS_##TYPENAME(EN_ENO_PARAMS, TYPENAME op){\ + TEST_EN(TYPENAME)\ + if (op < 0)\ + return -op;\ + return op;\ +} +__ANY_REAL(__iec_) +__ANY_SINT(__iec_) +#undef __iec_ + +#define __iec_(TYPENAME) \ +static inline TYPENAME ABS_##TYPENAME(EN_ENO_PARAMS, TYPENAME op){\ + TEST_EN(TYPENAME)\ + return op;\ +} +__ANY_UINT(__iec_) +#undef __iec_ + +/* overloaded function */ +#define __iec_(TYPENAME) \ +static inline TYPENAME ABS__##TYPENAME##__##TYPENAME(EN_ENO_PARAMS, TYPENAME op){\ + TEST_EN(TYPENAME)\ + if (op < 0)\ + return -op;\ + return op;\ +} +__ANY_REAL(__iec_) +__ANY_SINT(__iec_) +#undef __iec_ + +#define __iec_(TYPENAME) \ +static inline TYPENAME ABS__##TYPENAME##__##TYPENAME(EN_ENO_PARAMS, TYPENAME op){\ + TEST_EN(TYPENAME)\ + return op;\ +} +__ANY_UINT(__iec_) +#undef __iec_ + + + /**************/ + /* SQRT */ + /**************/ +/* explicitly typed function */ +#define __iec_(TYPENAME) \ +__numeric(SQRT_, TYPENAME, sqrt) /* explicitly typed function */\ +__numeric(SQRT__##TYPENAME##__, TYPENAME, sqrt) /* overloaded function */ +__ANY_REAL(__iec_) +#undef __iec_ + + /**************/ + /* LN */ + /**************/ +#define __iec_(TYPENAME) \ +__numeric(LN_, TYPENAME, log) /* explicitly typed function */\ +__numeric(LN__##TYPENAME##__, TYPENAME, log) /* overloaded function */ +__ANY_REAL(__iec_) +#undef __iec_ + + + /**************/ + /* LOG */ + /**************/ +#define __iec_(TYPENAME) \ +__numeric(LOG_, TYPENAME, log10) /* explicitly typed function */\ +__numeric(LOG__##TYPENAME##__, TYPENAME, log10) /* overloaded function */ +__ANY_REAL(__iec_) +#undef __iec_ + + /**************/ + /* EXP */ + /**************/ +#define __iec_(TYPENAME) \ +__numeric(EXP_, TYPENAME, exp) /* explicitly typed function */\ +__numeric(EXP__##TYPENAME##__, TYPENAME, exp) /* overloaded function */ +__ANY_REAL(__iec_) +#undef __iec_ + + + /**************/ + /* SIN */ + /**************/ +#define __iec_(TYPENAME) \ +__numeric(SIN_, TYPENAME, sin) /* explicitly typed function */\ +__numeric(SIN__##TYPENAME##__, TYPENAME, sin) /* overloaded function */ +__ANY_REAL(__iec_) +#undef __iec_ + + + /**************/ + /* COS */ + /**************/ +#define __iec_(TYPENAME) \ +__numeric(COS_, TYPENAME, cos) /* explicitly typed function */\ +__numeric(COS__##TYPENAME##__, TYPENAME, cos) /* overloaded function */ +__ANY_REAL(__iec_) +#undef __iec_ + + /**************/ + /* TAN */ + /**************/ +#define __iec_(TYPENAME) \ +__numeric(TAN_, TYPENAME, tan) /* explicitly typed function */\ +__numeric(TAN__##TYPENAME##__, TYPENAME, tan) /* overloaded function */ +__ANY_REAL(__iec_) +#undef __iec_ + + + /**************/ + /* ASIN */ + /**************/ +#define __iec_(TYPENAME) \ +__numeric(ASIN_, TYPENAME, asin) /* explicitly typed function */\ +__numeric(ASIN__##TYPENAME##__, TYPENAME, asin) /* overloaded function */ +__ANY_REAL(__iec_) +#undef __iec_ + + /**************/ + /* ACOS */ + /**************/ +#define __iec_(TYPENAME) \ +__numeric(ACOS_, TYPENAME, acos) /* explicitly typed function */\ +__numeric(ACOS__##TYPENAME##__, TYPENAME, acos) /* overloaded function */ +__ANY_REAL(__iec_) +#undef __iec_ + + /**************/ + /* ATAN */ + /**************/ +#define __iec_(TYPENAME) \ +__numeric(ATAN_, TYPENAME, atan) /* explicitly typed function */\ +__numeric(ATAN__##TYPENAME##__, TYPENAME, atan) /* overloaded function */ +__ANY_REAL(__iec_) +#undef __iec_ + + + +/*****************************************************/ +/*** Table 24 - Standard arithmetic functions ***/ +/*****************************************************/ +/* + Unfortunately, the following does not work!! + +#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int)) + #define __arith_expand(fname,TYPENAME, OP) \ -static inline TYPENAME fname##TYPENAME(EN_ENO_PARAMS, UINT param_count, TYPENAME op1, ...){\ +#define fname(EN, ENO, ...) fname__(EN, ENO, NUMARGS(__VA_ARGS__), __VA_ARGS__)\ +static inline TYPENAME fname__(EN_ENO_PARAMS, UINT param_count, TYPENAME op1, ...){\ + va_list ap;\ + UINT i;\ + TEST_EN(TYPENAME)\ + \ + va_start (ap, op1); \ + \ + for (i = 0; i < param_count - 1; i++){\ + op1 = op1 OP va_arg (ap, VA_ARGS_##TYPENAME);\ + }\ + \ + va_end (ap); \ + return op1;\ +} +*/ + + +#define __arith_expand(fname,TYPENAME, OP) \ +static inline TYPENAME fname(EN_ENO_PARAMS, UINT param_count, TYPENAME op1, ...){\ va_list ap;\ UINT i;\ TEST_EN(TYPENAME)\ @@ -861,291 +1133,353 @@ } #define __arith_static(fname,TYPENAME, OP) \ -static inline TYPENAME fname##TYPENAME(EN_ENO_PARAMS, TYPENAME op1, TYPENAME op2){\ +static inline TYPENAME fname(EN_ENO_PARAMS, TYPENAME op1, TYPENAME op2){\ TEST_EN(TYPENAME)\ return op1 OP op2;\ } -/**************/ -/* ADD */ -/**************/ -#define __add_(TYPENAME) __arith_expand(__add_, TYPENAME, + ) -ANY_NUM(__add_) - -/**************/ -/* MUL */ -/**************/ -#define __mul_(TYPENAME) __arith_expand(__mul_, TYPENAME, * ) -ANY_NUM(__mul_) - -/**************/ -/* SUB */ -/**************/ -#define __sub_(TYPENAME) __arith_static(__sub_, TYPENAME, - ) -ANY_NUM(__sub_) - -/**************/ -/* DIV */ -/**************/ -#define __div_(TYPENAME)\ -static inline TYPENAME __div_##TYPENAME(EN_ENO_PARAMS, TYPENAME op1, TYPENAME op2){\ + /**************/ + /* ADD */ + /**************/ +#define __iec_(TYPENAME) \ +__arith_expand(ADD_##TYPENAME, TYPENAME, +) /* explicitly typed function */\ +__arith_expand(ADD__##TYPENAME##__##TYPENAME, TYPENAME, +) /* overloaded function */ +__ANY_NUM(__iec_) +#undef __iec_ + + /**************/ + /* MUL */ + /**************/ +#define __iec_(TYPENAME) \ +__arith_expand(MUL_##TYPENAME, TYPENAME, *) /* explicitly typed function */\ +__arith_expand(MUL__##TYPENAME##__##TYPENAME, TYPENAME, *) /* overloaded function */ +__ANY_NUM(__iec_) +#undef __iec_ + + /**************/ + /* SUB */ + /**************/ +#define __iec_(TYPENAME) \ +__arith_expand(SUB_##TYPENAME, TYPENAME, -) /* explicitly typed function */\ +__arith_expand(SUB__##TYPENAME##__##TYPENAME##__##TYPENAME, TYPENAME, -) /* overloaded function */ +__ANY_NUM(__iec_) +#undef __iec_ + + /**************/ + /* DIV */ + /**************/ +/* The explicitly typed standard functions */ +#define __iec_(TYPENAME)\ +static inline TYPENAME DIV_##TYPENAME(EN_ENO_PARAMS, TYPENAME op1, TYPENAME op2){\ TEST_EN_COND(TYPENAME, op2 == 0)\ return op1 / op2;\ } -ANY_NUM(__div_) - -/**************/ -/* MOD */ -/**************/ -#define __mod_(TYPENAME) __arith_static(__mod_, TYPENAME, % ) -ANY_INT(__mod_) - -/**************/ -/* AND */ -/**************/ -__arith_expand(__and_, BOOL, && ) -#define __and_(TYPENAME) __arith_expand(__and_, TYPENAME, & ) -ANY_NBIT(__and_) - -/*************/ -/* OR */ -/*************/ -__arith_expand(__or_, BOOL, || ) -#define __or_(TYPENAME) __arith_expand(__or_, TYPENAME, |) -ANY_NBIT(__or_) - -/**************/ -/* XOR */ -/**************/ -static inline BOOL __xor_BOOL(EN_ENO_PARAMS, UINT param_count, BOOL op1, ...){ - va_list ap; - UINT i; - TEST_EN(BOOL) - - va_start (ap, op1); /* Initialize the argument list. */ - - for (i = 0; i < param_count - 1; i++){ - BOOL tmp = va_arg (ap, VA_ARGS_BOOL); - op1 = (op1 && !tmp) || (!op1 && tmp); - } - - va_end (ap); /* Clean up. */ - return op1; -} -#define __xor_(TYPENAME) __arith_expand(__xor_, TYPENAME, ^) -ANY_NBIT(__xor_) - -/**************/ -/* NOT */ -/**************/ -static inline BOOL __not_BOOL(EN_ENO_PARAMS, BOOL op1){ +__ANY_NUM(__iec_) +#undef __iec_ + +/* The overloaded standard functions */ +#define __iec_(TYPENAME)\ +static inline TYPENAME DIV__##TYPENAME##__##TYPENAME##__##TYPENAME(EN_ENO_PARAMS, TYPENAME op1, TYPENAME op2){\ + TEST_EN_COND(TYPENAME, op2 == 0)\ + return op1 / op2;\ +} +__ANY_NUM(__iec_) +#undef __iec_ + + /**************/ + /* MOD */ + /**************/ +/* The explicitly typed standard functions */ +#define __iec_(TYPENAME)\ +__arith_expand(MOD_##TYPENAME, TYPENAME, %) /* explicitly typed function */\ +__arith_expand(MOD__##TYPENAME##__##TYPENAME##__##TYPENAME, TYPENAME, %) /* overloaded function */ +__ANY_INT(__iec_) +#undef __iec_ + + /**************/ + /* EXPT */ + /**************/ +/* overloaded function */ +#define __iec_(in1_TYPENAME,in2_TYPENAME) \ +static inline in1_TYPENAME EXPT__##in1_TYPENAME##__##in1_TYPENAME##__##in2_TYPENAME\ + (EN_ENO_PARAMS, in1_TYPENAME IN1, in2_TYPENAME IN2){\ + TEST_EN(in1_TYPENAME)\ + return pow(IN1, IN2);\ +} +#define __in1_anyreal_(in2_TYPENAME) __ANY_REAL_1(__iec_,in2_TYPENAME) +__ANY_NUM(__in1_anyreal_) +#undef __iec_ + + + + /***************/ + /* MOVE */ + /***************/ +/* The explicitly typed standard functions */ +#define __iec_(TYPENAME)\ +static inline TYPENAME MOVE_##TYPENAME(EN_ENO_PARAMS, TYPENAME op1){\ + TEST_EN(TYPENAME)\ + return op1;\ +} +__ANY(__iec_) +#undef __iec_ + +/* Overloaded function */ +#define __iec_(TYPENAME)\ +static inline TYPENAME MOVE__##TYPENAME##__##TYPENAME(EN_ENO_PARAMS, TYPENAME op1){\ + TEST_EN(TYPENAME)\ + return op1;\ +} +__ANY(__iec_) +#undef __iec_ + + + + + + +/***********************************/ +/***********************************/ +/* 2.5.1.5.3 Bit String Functions */ +/***********************************/ +/***********************************/ + +/****************************************************/ +/*** Table 25 - Standard bit shift functions ***/ +/****************************************************/ + +/* We do not delcare explcitly typed versions of the functions in table 25. + * See note above regarding explicitly typed functions for more details. + */ +#define __in1_anynbit_(in2_TYPENAME) __ANY_NBIT_1(__iec_,in2_TYPENAME) + +#define __shift_(fname, in1_TYPENAME, in2_TYPENAME, OP)\ +static inline in1_TYPENAME fname(EN_ENO_PARAMS, in1_TYPENAME IN, in2_TYPENAME N) {\ + TEST_EN(in1_TYPENAME)\ + return IN OP N;\ +} + + /**************/ + /* SHL */ + /**************/ +#define __iec_(TYPENAME) \ +/* Overloaded function */\ +static inline BOOL SHL__BOOL__##TYPENAME(EN_ENO_PARAMS, BOOL IN, TYPENAME N) { \ + TEST_EN(BOOL);\ + return (N==0)? IN : __INIT_BOOL; /* shifting by N>1 will always introduce a 0 */\ +} +__ANY_INT(__iec_) +#undef __iec_ + + +#define __iec_(in1_TYPENAME,in2_TYPENAME) \ +__shift_(SHL__##in1_TYPENAME##__##in1_TYPENAME##__##in2_TYPENAME, in1_TYPENAME, in2_TYPENAME, << )/* Overloaded function */ +__ANY_INT(__in1_anynbit_) +#undef __iec_ + + + /**************/ + /* SHR */ + /**************/ +#define __iec_(TYPENAME) \ +/* Overloaded function */\ +static inline BOOL SHR__BOOL__##TYPENAME(EN_ENO_PARAMS, BOOL IN, TYPENAME N) { \ + TEST_EN(BOOL);\ + return (N==0)? IN : __INIT_BOOL; /* shifting by N>1 will always introduce a 0 */\ +} +__ANY_INT(__iec_) +#undef __iec_ + + +#define __iec_(in1_TYPENAME,in2_TYPENAME) \ +__shift_(SHR__##in1_TYPENAME##__##in1_TYPENAME##__##in2_TYPENAME, in1_TYPENAME, in2_TYPENAME, >> )/* Overloaded function */ +__ANY_INT(__in1_anynbit_) +#undef __iec_ + + + /**************/ + /* ROR */ + /**************/ +#define __iec_(TYPENAME) \ +/* Overloaded function */\ +static inline BOOL ROR__BOOL__##TYPENAME(EN_ENO_PARAMS, BOOL IN, TYPENAME N) { \ + TEST_EN(BOOL);\ + return IN; /* rotating a single bit by any value N will not change that bit! */\ +} +__ANY_INT(__iec_) +#undef __iec_ + + +#define __iec_(in1_TYPENAME,in2_TYPENAME) \ +static inline in1_TYPENAME ROR__##in1_TYPENAME##__##in1_TYPENAME##__##in2_TYPENAME(EN_ENO_PARAMS, in1_TYPENAME IN, in2_TYPENAME N){\ + TEST_EN(in1_TYPENAME)\ + N %= 8*sizeof(in1_TYPENAME);\ + return (IN >> N) | (IN << (8*sizeof(in1_TYPENAME)-N));\ +} +__ANY_INT(__in1_anynbit_) +#undef __iec_ + + + /**************/ + /* ROL */ + /**************/ +#define __iec_(TYPENAME) \ +/* Overloaded function */\ +static inline BOOL ROL__BOOL__##TYPENAME(EN_ENO_PARAMS, BOOL IN, TYPENAME N) { \ + TEST_EN(BOOL);\ + return IN; /* rotating a single bit by any value N will not change that bit! */\ +} +__ANY_INT(__iec_) +#undef __iec_ + + +#define __iec_(in1_TYPENAME,in2_TYPENAME) \ +static inline in1_TYPENAME ROL__##in1_TYPENAME##__##in1_TYPENAME##__##in2_TYPENAME(EN_ENO_PARAMS, in1_TYPENAME IN, in2_TYPENAME N){\ + TEST_EN(in1_TYPENAME)\ + N %= 8*sizeof(in1_TYPENAME);\ + return (IN << N) | (IN >> (8*sizeof(in1_TYPENAME)-N));\ +} +__ANY_INT(__in1_anynbit_) +#undef __iec_ + + + +/*********************/ +/*** Table 26 ***/ +/*********************/ + + /**************/ + /* AND */ + /**************/ +__arith_expand(AND_BOOL, BOOL, && ) /* The explicitly typed standard functions */ +__arith_expand(AND__BOOL__BOOL, BOOL, && ) /* Overloaded function */ + +#define __iec_(TYPENAME) \ +__arith_expand(AND_##TYPENAME, TYPENAME, &) /* The explicitly typed standard functions */\ +__arith_expand(AND__##TYPENAME##__##TYPENAME, TYPENAME, &) /* Overloaded function */ +__ANY_NBIT(__iec_) +#undef __iec_ + + /*************/ + /* OR */ + /*************/ +__arith_expand(OR_BOOL, BOOL, || ) /* The explicitly typed standard functions */ +__arith_expand(OR__BOOL__BOOL, BOOL, || ) /* Overloaded function */ + +#define __iec_(TYPENAME) \ +__arith_expand(OR_##TYPENAME, TYPENAME, |) /* The explicitly typed standard functions */\ +__arith_expand(OR__##TYPENAME##__##TYPENAME, TYPENAME, |) /* Overloaded function */ +__ANY_NBIT(__iec_) +#undef __iec_ + + /**************/ + /* XOR */ + /**************/ +#define __xorbool_expand(fname) \ +static inline BOOL fname(EN_ENO_PARAMS, UINT param_count, BOOL op1, ...){ \ + va_list ap; \ + UINT i; \ + TEST_EN(BOOL) \ +\ + va_start (ap, op1); /* Initialize the argument list. */ \ +\ + for (i = 0; i < param_count - 1; i++){ \ + BOOL tmp = va_arg (ap, VA_ARGS_BOOL); \ + op1 = (op1 && !tmp) || (!op1 && tmp); \ + } \ +\ + va_end (ap); /* Clean up. */ \ + return op1; \ +} + +__xorbool_expand(XOR_BOOL) /* The explicitly typed standard functions */ +__xorbool_expand(XOR__BOOL__BOOL) /* Overloaded function */ + +#define __iec_(TYPENAME) \ +__arith_expand(XOR_##TYPENAME, TYPENAME, ^) /* The explicitly typed standard functions */\ +__arith_expand(XOR__##TYPENAME##__##TYPENAME, TYPENAME, ^) /* Overloaded function */\ +__ANY_NBIT(__iec_) +#undef __iec_ + + + /**************/ + /* NOT */ + /**************/ +/* The explicitly typed standard functions */ +static inline BOOL NOT_BOOL(EN_ENO_PARAMS, BOOL op1){ TEST_EN(BOOL) return !op1; } -#define __not_(TYPENAME)\ -static inline TYPENAME __not_##TYPENAME(EN_ENO_PARAMS, TYPENAME op1){\ +/* Overloaded function */ +static inline BOOL NOT__BOOL__BOOL(EN_ENO_PARAMS, BOOL op1){ + TEST_EN(BOOL) + return !op1; +} + +/* The explicitly typed standard functions */ +#define __iec_(TYPENAME)\ +static inline TYPENAME NOT_##TYPENAME(EN_ENO_PARAMS, TYPENAME op1){\ TEST_EN(TYPENAME)\ return ~op1;\ } -ANY_NBIT(__not_) - -/***************/ -/* MOVE */ -/***************/ -#define __move_(TYPENAME)\ -static inline TYPENAME __move_##TYPENAME(EN_ENO_PARAMS, TYPENAME op1){\ +__ANY_NBIT(__iec_) +#undef __iec_ + +/* Overloaded function */ +#define __iec_(TYPENAME)\ +static inline TYPENAME NOT__##TYPENAME##__##TYPENAME(EN_ENO_PARAMS, TYPENAME op1){\ TEST_EN(TYPENAME)\ - return op1;\ -} -ANY(__move_) - -/**************/ -/* Binary ops */ -/**************/ -#define __shift_(fname, TYPENAME, OP)\ -static inline TYPENAME fname##TYPENAME(EN_ENO_PARAMS, TYPENAME IN, USINT N) {\ - TEST_EN(TYPENAME)\ - return IN OP N;\ -} - -#define __shl_(TYPENAME) __shift_(__shl_, TYPENAME, << ) -/* Call previously defined macro for each ANY_NBIT */ -ANY_NBIT(__shl_) - -#define __shr_(TYPENAME) __shift_(__shr_, TYPENAME, >> ) -/* Call previously defined macro for each ANY_NBIT */ -ANY_NBIT(__shr_) - -#define __ror_(TYPENAME)\ -static inline TYPENAME __ror_##TYPENAME(EN_ENO_PARAMS, TYPENAME IN, USINT N){\ - TEST_EN(TYPENAME)\ - N %= 8*sizeof(TYPENAME);\ - return (IN >> N) | (IN << (8*sizeof(TYPENAME)-N));\ -} -/* Call previously defined macro for each ANY_NBIT */ -ANY_NBIT(__ror_) - -#define __rol_(TYPENAME)\ -static inline TYPENAME __rol_##TYPENAME(EN_ENO_PARAMS, TYPENAME IN, USINT N){\ - TEST_EN(TYPENAME)\ - N %= 8*sizeof(TYPENAME);\ - return (IN << N) | (IN >> (8*sizeof(TYPENAME)-N));\ -} -/* Call previously defined macro for each ANY_NBIT */ -ANY_NBIT(__rol_) - -/*******************************************/ -/* Arithmetic and bitwise functions */ -/*******************************************/ - -#define __numeric(fname,TYPENAME, FUNC) \ -static inline TYPENAME fname##TYPENAME(EN_ENO_PARAMS, TYPENAME op){\ - TEST_EN(TYPENAME)\ - return FUNC(op);\ -} - - /**************/ - /* ABS */ - /**************/ -#define __abs_signed(TYPENAME) \ -static inline TYPENAME __abs_##TYPENAME(EN_ENO_PARAMS, TYPENAME op){\ - TEST_EN(TYPENAME)\ - if (op < 0)\ - return -op;\ - return op;\ -} -ANY_REAL(__abs_signed) -ANY_SINT(__abs_signed) - -#define __abs_unsigned(TYPENAME) \ -static inline TYPENAME __abs_##TYPENAME(EN_ENO_PARAMS, TYPENAME op){\ - TEST_EN(TYPENAME)\ - return op;\ -} -ANY_UINT(__abs_unsigned) - - /**************/ - /* SQRT */ - /**************/ -#define __sqrt_(TYPENAME) __numeric(__sqrt_, TYPENAME, sqrt) -ANY_REAL(__sqrt_) - - /**************/ - /* LN */ - /**************/ -#define __ln_(TYPENAME) __numeric(__ln_, TYPENAME, log) -ANY_REAL(__ln_) - - /**************/ - /* LOG */ - /**************/ -#define __log_(TYPENAME) __numeric(__log_, TYPENAME, log10) -ANY_REAL(__log_) - - /**************/ - /* EXP */ - /**************/ -#define __exp_(TYPENAME) __numeric(__exp_, TYPENAME, exp) -ANY_REAL(__exp_) - - /**************/ - /* SIN */ - /**************/ -#define __sin_(TYPENAME) __numeric(__sin_, TYPENAME, sin) -ANY_REAL(__sin_) - - /**************/ - /* COS */ - /**************/ -#define __cos_(TYPENAME) __numeric(__cos_, TYPENAME, cos) -ANY_REAL(__cos_) - - /**************/ - /* TAN */ - /**************/ -#define __tan_(TYPENAME) __numeric(__tan_, TYPENAME, tan) -ANY_REAL(__tan_) - - /**************/ - /* ASIN */ - /**************/ -#define __asin_(TYPENAME) __numeric(__asin_, TYPENAME, asin) -ANY_REAL(__asin_) - - /**************/ - /* ACOS */ - /**************/ -#define __acos_(TYPENAME) __numeric(__acos_, TYPENAME, acos) -ANY_REAL(__acos_) - - /**************/ - /* ATAN */ - /**************/ -#define __atan_(TYPENAME) __numeric(__atan_, TYPENAME, atan) -ANY_REAL(__atan_) - - /**************/ - /* EXPT */ - /**************/ -#define __expt_(TYPENAME)\ -static inline TYPENAME __expt_##TYPENAME(EN_ENO_PARAMS, TYPENAME IN1, REAL IN2){\ - TEST_EN(TYPENAME)\ - return pow(IN1, IN2);\ -}ANY_REAL(__expt_) - -/**************/ -/* Selection */ -/**************/ - - /**************/ - /* SEL */ - /**************/ - -#define __sel_(TYPENAME)\ -static inline TYPENAME __sel_##TYPENAME(EN_ENO_PARAMS, BOOL G, TYPENAME op0, TYPENAME op1){\ + return ~op1;\ +} +__ANY_NBIT(__iec_) +#undef __iec_ + + + + + + +/***************************************************/ +/***************************************************/ +/* 2.5.1.5.4 Selection and comparison Functions */ +/***************************************************/ +/***************************************************/ + +/*********************/ +/*** Table 27 ***/ +/*********************/ + + + /**************/ + /* SEL */ + /**************/ + +/* The explicitly typed standard functions */ +#define __iec_(TYPENAME)\ +static inline TYPENAME SEL_##TYPENAME(EN_ENO_PARAMS, BOOL G, TYPENAME op0, TYPENAME op1){\ TEST_EN(TYPENAME)\ return G ? op1 : op0;\ } -ANY(__sel_) - - /**************/ - /* limit */ - /**************/ - -#define __limit_(TYPENAME)\ -static inline TYPENAME __limit_##TYPENAME(EN_ENO_PARAMS, TYPENAME MN, TYPENAME IN, TYPENAME MX){\ +__ANY(__iec_) +#undef __iec_ + +/* Overloaded function */ +#define __iec_(TYPENAME)\ +static inline TYPENAME SEL__##TYPENAME##__BOOL__##TYPENAME##__##TYPENAME(EN_ENO_PARAMS, BOOL G, TYPENAME op0, TYPENAME op1){\ TEST_EN(TYPENAME)\ - return IN > MN ? IN < MX ? IN : MX : MN;\ -} - -/* Call previously defined macro for each concerned type */ -ANY_NBIT(__limit_) -ANY_NUM(__limit_) - -#define __limit_time(TYPENAME)\ -static inline TYPENAME __limit_##TYPENAME(EN_ENO_PARAMS, TYPENAME MN, TYPENAME IN, TYPENAME MX){\ - TEST_EN(TYPENAME)\ - return __TIME_CMP(IN, MN) > 0 ? /* IN>MN ?*/\ - __TIME_CMP(IN, MX) < 0 ? /* IN 0 ? __STR_CMP(IN, MX) < 0 ? IN : MX : MN; -} + return G ? op1 : op0;\ +} +__ANY(__iec_) +#undef __iec_ + /**************/ /* MAX */ /**************/ #define __extrem_(fname,TYPENAME, COND) \ -static inline TYPENAME fname##TYPENAME(EN_ENO_PARAMS, UINT param_count, TYPENAME op1, ...){\ +static inline TYPENAME fname(EN_ENO_PARAMS, UINT param_count, TYPENAME op1, ...){\ va_list ap;\ UINT i;\ TEST_EN(TYPENAME)\ @@ -1161,52 +1495,130 @@ return op1;\ } -#define __max_num(TYPENAME) __extrem_(__max_,TYPENAME, op1 < tmp) -ANY_NBIT(__max_num) -ANY_NUM(__max_num) - -__extrem_(__max_, STRING, __STR_CMP(op1,tmp) < 0) -#define __max_time(TYPENAME) __extrem_(__max_, TYPENAME, __TIME_CMP(op1, tmp) < 0) - -/* Call previously defined macro for each concerned type */ -ANY_DATE(__max_time) -__max_time(TIME) +/* Max for numerical data types */ +#define __iec_(TYPENAME) \ +__extrem_(MAX_##TYPENAME,TYPENAME, op1 < tmp) /* The explicitly typed standard functions */\ +__extrem_(MAX__##TYPENAME##__##TYPENAME,TYPENAME, op1 < tmp) /* Overloaded function */ +__ANY_BIT(__iec_) +__ANY_NUM(__iec_) +#undef __iec_ + +/* Max for time data types */ +#define __iec_(TYPENAME) \ +__extrem_(MAX_##TYPENAME, TYPENAME, __time_cmp(op1, tmp) < 0) /* The explicitly typed standard functions */\ +__extrem_(MAX__##TYPENAME##__##TYPENAME, TYPENAME, __time_cmp(op1, tmp) < 0) /* Overloaded function */ +__ANY_DATE(__iec_) +__iec_(TIME) +#undef __iec_ + +/* Max for string data types */ +__extrem_(MAX_STRING, STRING, __STR_CMP(op1,tmp) < 0) /* The explicitly typed standard functions */ +__extrem_(MAX__STRING__STRING, STRING, __STR_CMP(op1,tmp) < 0) /* Overloaded function */ /**************/ /* MIN */ /**************/ -#define __min_num(TYPENAME) __extrem_(__min_, TYPENAME, op1 > tmp) -ANY_NBIT(__min_num) -ANY_NUM(__min_num) - -__extrem_(__min_, STRING, __STR_CMP(op1,tmp) > 0) - -#define __min_time(TYPENAME) __extrem_(__min_, TYPENAME, __TIME_CMP(op1, tmp) > 0) - -/* Call previously defined macro for each concerned type */ -ANY_DATE(__min_time) -__min_time(TIME) +/* Min for numerical data types */ +#define __iec_(TYPENAME) \ +__extrem_(MIN_##TYPENAME, TYPENAME, op1 > tmp) /* The explicitly typed standard functions */\ +__extrem_(MIN__##TYPENAME##__##TYPENAME, TYPENAME, op1 > tmp) /* Overloaded function */ +__ANY_NBIT(__iec_) +__ANY_NUM(__iec_) +#undef __iec_ + +/* Min for time data types */ +#define __iec_(TYPENAME) \ +__extrem_(MIN_##TYPENAME, TYPENAME, __time_cmp(op1, tmp) > 0) /* The explicitly typed standard functions */\ +__extrem_(MIN__##TYPENAME##__##TYPENAME, TYPENAME, __time_cmp(op1, tmp) > 0) /* Overloaded function */ +__ANY_DATE(__iec_) +__iec_(TIME) +#undef __iec_ + +/* Min for string data types */ +__extrem_(MIN_STRING, STRING, __STR_CMP(op1,tmp) > 0) /* The explicitly typed standard functions */ +__extrem_(MIN__STRING__STRING, STRING, __STR_CMP(op1,tmp) > 0) /* Overloaded function */ + + /**************/ + /* LIMIT */ + /**************/ + +/* Limit for numerical data types */ +#define __iec_(TYPENAME)\ +/* The explicitly typed standard functions */\ +static inline TYPENAME LIMIT_##TYPENAME(EN_ENO_PARAMS, TYPENAME MN, TYPENAME IN, TYPENAME MX){\ + TEST_EN(TYPENAME)\ + return IN > MN ? IN < MX ? IN : MX : MN;\ +}\ +/* Overloaded function */\ +static inline TYPENAME LIMIT__##TYPENAME##__##TYPENAME##__##TYPENAME##__##TYPENAME(EN_ENO_PARAMS, TYPENAME MN, TYPENAME IN, TYPENAME MX){\ + TEST_EN(TYPENAME)\ + return IN > MN ? IN < MX ? IN : MX : MN;\ +} +__ANY_NBIT(__iec_) +__ANY_NUM(__iec_) +#undef __iec_ + + +/* Limit for time data types */ +#define __iec_(TYPENAME)\ +/* The explicitly typed standard functions */\ +static inline TYPENAME LIMIT_##TYPENAME(EN_ENO_PARAMS, TYPENAME MN, TYPENAME IN, TYPENAME MX){\ + TEST_EN(TYPENAME)\ + return __time_cmp(IN, MN) > 0 ? /* IN>MN ?*/\ + __time_cmp(IN, MX) < 0 ? /* IN 0 ? /* IN>MN ?*/\ + __time_cmp(IN, MX) < 0 ? /* IN 0 ? __STR_CMP(IN, MX) < 0 ? IN : MX : MN; +} + +/* Overloaded function */ +static inline STRING LIMIT__STRING__STRING__STRING__STRING(EN_ENO_PARAMS, STRING MN, STRING IN, STRING MX){ + TEST_EN(STRING) + return __STR_CMP(IN, MN) > 0 ? __STR_CMP(IN, MX) < 0 ? IN : MX : MN; +} + /**************/ /* MUX */ /**************/ -#define __mux_(TYPENAME) \ -static inline TYPENAME __mux_##TYPENAME(EN_ENO_PARAMS, UINT param_count, UINT K, ...){\ +/* The standard states that the inputs for SEL and MUX must be named starting off from 0, + * unlike remaining functions, that start off at 1. + */ +/* The explicitly typed standard functions */ +#define __in1_anyint_(in2_TYPENAME) __ANY_INT_1(__iec_,in2_TYPENAME) +#define __iec_(in1_TYPENAME,in2_TYPENAME) \ +static inline in2_TYPENAME MUX__##in2_TYPENAME##__##in1_TYPENAME##__##in2_TYPENAME(EN_ENO_PARAMS, UINT param_count, in1_TYPENAME K, ...){\ va_list ap;\ UINT i;\ - TYPENAME tmp;\ - TEST_EN_COND(TYPENAME, K >= param_count)\ - tmp = __INIT_##TYPENAME;\ + in2_TYPENAME tmp;\ + TEST_EN_COND(in2_TYPENAME, K >= param_count)\ + tmp = __INIT_##in2_TYPENAME;\ \ va_start (ap, K); /* Initialize the argument list. */\ \ for (i = 0; i < param_count; i++){\ if(K == i){\ - tmp = va_arg (ap, VA_ARGS_##TYPENAME);\ + tmp = va_arg (ap, VA_ARGS_##in2_TYPENAME);\ va_end (ap); /* Clean up. */\ return tmp;\ }else{\ - va_arg (ap, VA_ARGS_##TYPENAME);\ + va_arg (ap, VA_ARGS_##in2_TYPENAME);\ }\ }\ \ @@ -1214,14 +1626,17 @@ return tmp;\ } -ANY(__mux_) - -/**************/ -/* Comparison */ -/**************/ +__ANY(__in1_anyint_) +#undef __iec_ + + +/******************************************/ +/*** Table 28 ***/ +/*** Standard comparison functions ***/ +/******************************************/ #define __compare_(fname,TYPENAME, COND) \ -static inline BOOL fname##TYPENAME(EN_ENO_PARAMS, UINT param_count, TYPENAME op1, ...){\ +static inline BOOL fname(EN_ENO_PARAMS, UINT param_count, TYPENAME op1, ...){\ va_list ap;\ UINT i;\ TEST_EN(BOOL)\ @@ -1246,91 +1661,537 @@ } #define __compare_num(fname, TYPENAME, TEST) __compare_(fname, TYPENAME, op1 TEST tmp ) -#define __compare_time(fname, TYPENAME, TEST) __compare_(fname, TYPENAME, __TIME_CMP(op1, tmp) TEST 0) +#define __compare_time(fname, TYPENAME, TEST) __compare_(fname, TYPENAME, __time_cmp(op1, tmp) TEST 0) #define __compare_string(fname, TEST) __compare_(fname, STRING, __STR_CMP(op1, tmp) TEST 0 ) /**************/ /* GT */ /**************/ - -#define __gt_num(TYPENAME) __compare_num(__gt_, TYPENAME, > ) -ANY_NBIT(__gt_num) -ANY_NUM(__gt_num) - -#define __gt_time(TYPENAME) __compare_time(__gt_, TYPENAME, > ) -ANY_DATE(__gt_time) -__gt_time(TIME) - -__compare_string(__gt_, > ) +/* Comparison for numerical data types */ +#define __iec_(TYPENAME) \ +__compare_num(GT_##TYPENAME, TYPENAME, > ) /* The explicitly typed standard functions */\ +__compare_num(GT__BOOL__##TYPENAME, TYPENAME, > ) /* Overloaded function */ +__ANY_NBIT(__iec_) +__ANY_NUM(__iec_) +#undef __iec_ + +/* Comparison for time data types */ +#define __iec_(TYPENAME) \ +__compare_time(GT_##TYPENAME, TYPENAME, > ) /* The explicitly typed standard functions */\ +__compare_time(GT__BOOL__##TYPENAME, TYPENAME, > ) /* Overloaded function */ +__ANY_DATE(__iec_) +__iec_(TIME) +#undef __iec_ + +/* Comparison for string data types */ +__compare_string(GT_STRING, > ) /* The explicitly typed standard functions */ +__compare_string(GT__BOOL__STRING, > ) /* Overloaded function */ /**************/ /* GE */ /**************/ - -#define __ge_num(TYPENAME) __compare_num(__ge_, TYPENAME, >= ) -ANY_BIT(__ge_num) -ANY_NUM(__ge_num) - -#define __ge_time(TYPENAME) __compare_time(__ge_, TYPENAME, >= ) -ANY_DATE(__ge_time) -__ge_time(TIME) - -__compare_string(__ge_, >=) +/* Comparison for numerical data types */ +#define __iec_(TYPENAME) \ +__compare_num(GE_##TYPENAME, TYPENAME, >= ) /* The explicitly typed standard functions */\ +__compare_num(GE__BOOL__##TYPENAME, TYPENAME, >= ) /* Overloaded function */ +__ANY_NBIT(__iec_) +__ANY_NUM(__iec_) +#undef __iec_ + +/* Comparison for time data types */ +#define __iec_(TYPENAME) \ +__compare_time(GE_##TYPENAME, TYPENAME, >= ) /* The explicitly typed standard functions */\ +__compare_time(GE__BOOL__##TYPENAME, TYPENAME, >= ) /* Overloaded function */ +__ANY_DATE(__iec_) +__iec_(TIME) +#undef __iec_ + +/* Comparison for string data types */ +__compare_string(GE_STRING, >= ) /* The explicitly typed standard functions */ +__compare_string(GE__BOOL__STRING, >= ) /* Overloaded function */ + + /**************/ /* EQ */ /**************/ - -#define __eq_num(TYPENAME) __compare_num(__eq_, TYPENAME, == ) -ANY_BIT(__eq_num) -ANY_NUM(__eq_num) - -#define __eq_time(TYPENAME) __compare_time(__eq_, TYPENAME, == ) -ANY_DATE(__eq_time) -__eq_time(TIME) - -__compare_string(__eq_, == ) +/* Comparison for numerical data types */ +#define __iec_(TYPENAME) \ +__compare_num(EQ_##TYPENAME, TYPENAME, == ) /* The explicitly typed standard functions */\ +__compare_num(EQ__BOOL__##TYPENAME, TYPENAME, == ) /* Overloaded function */ +__ANY_NBIT(__iec_) +__ANY_NUM(__iec_) +#undef __iec_ + +/* Comparison for time data types */ +#define __iec_(TYPENAME) \ +__compare_time(EQ_##TYPENAME, TYPENAME, == ) /* The explicitly typed standard functions */\ +__compare_time(EQ__BOOL__##TYPENAME, TYPENAME, == ) /* Overloaded function */ +__ANY_DATE(__iec_) +__iec_(TIME) +#undef __iec_ + +/* Comparison for string data types */ +__compare_string(EQ_STRING, == ) /* The explicitly typed standard functions */ +__compare_string(EQ__BOOL__STRING, == ) /* Overloaded function */ + /**************/ /* LT */ /**************/ - -#define __lt_num(TYPENAME) __compare_num(__lt_, TYPENAME, < ) -ANY_BIT(__lt_num) -ANY_NUM(__lt_num) - -#define __lt_time(TYPENAME) __compare_time(__lt_, TYPENAME, < ) -ANY_DATE(__lt_time) -__lt_time(TIME) - -__compare_string(__lt_, < ) +/* Comparison for numerical data types */ +#define __iec_(TYPENAME) \ +__compare_num(LT_##TYPENAME, TYPENAME, < ) /* The explicitly typed standard functions */\ +__compare_num(LT__BOOL__##TYPENAME, TYPENAME, < ) /* Overloaded function */ +__ANY_NBIT(__iec_) +__ANY_NUM(__iec_) +#undef __iec_ + +/* Comparison for time data types */ +#define __iec_(TYPENAME) \ +__compare_time(LT_##TYPENAME, TYPENAME, < ) /* The explicitly typed standard functions */\ +__compare_time(LT__BOOL__##TYPENAME, TYPENAME, < ) /* Overloaded function */ +__ANY_DATE(__iec_) +__iec_(TIME) +#undef __iec_ + +/* Comparison for string data types */ +__compare_string(LT_STRING, < ) /* The explicitly typed standard functions */ +__compare_string(LT__BOOL__STRING, < ) /* Overloaded function */ + /**************/ /* LE */ /**************/ - -#define __le_num(TYPENAME) __compare_num(__le_, TYPENAME, <= ) -ANY_BIT(__le_num) -ANY_NUM(__le_num) - -#define __le_time(TYPENAME) __compare_time(__le_, TYPENAME, <= ) -ANY_DATE(__le_time) -__le_time(TIME) - -__compare_string(__le_, <= ) +/* Comparison for numerical data types */ +#define __iec_(TYPENAME) \ +__compare_num(LE_##TYPENAME, TYPENAME, <= ) /* The explicitly typed standard functions */\ +__compare_num(LE__BOOL__##TYPENAME, TYPENAME, <= ) /* Overloaded function */ +__ANY_NBIT(__iec_) +__ANY_NUM(__iec_) +#undef __iec_ + +/* Comparison for time data types */ +#define __iec_(TYPENAME) \ +__compare_time(LE_##TYPENAME, TYPENAME, <= ) /* The explicitly typed standard functions */\ +__compare_time(LE__BOOL__##TYPENAME, TYPENAME, <= ) /* Overloaded function */ +__ANY_DATE(__iec_) +__iec_(TIME) +#undef __iec_ + +/* Comparison for string data types */ +__compare_string(LE_STRING, <= ) /* The explicitly typed standard functions */ +__compare_string(LE__BOOL__STRING, <= ) /* Overloaded function */ + /**************/ /* NE */ /**************/ - -#define __ne_num(TYPENAME) __compare_num(__ne_, TYPENAME, != ) -ANY_BIT(__ne_num) -ANY_NUM(__ne_num) - -#define __ne_time(TYPENAME) __compare_time(__ne_, TYPENAME, != ) -ANY_DATE(__ne_time) -__ne_time(TIME) - -__compare_string(__ne_, != ) - +/* Comparison for numerical data types */ +#define __iec_(TYPENAME) \ +__compare_num(NE_##TYPENAME, TYPENAME, != ) /* The explicitly typed standard functions */\ +__compare_num(NE__BOOL__##TYPENAME##__##TYPENAME, TYPENAME, != ) /* Overloaded function */ +__ANY_NBIT(__iec_) +__ANY_NUM(__iec_) +#undef __iec_ + +/* Comparison for time data types */ +#define __iec_(TYPENAME) \ +__compare_time(NE_##TYPENAME, TYPENAME, != ) /* The explicitly typed standard functions */\ +__compare_time(NE__BOOL__##TYPENAME##__##TYPENAME, TYPENAME, != ) /* Overloaded function */ +__ANY_DATE(__iec_) +__iec_(TIME) +#undef __iec_ + +/* Comparison for string data types */ +__compare_string(NE_STRING, != ) /* The explicitly typed standard functions */ +__compare_string(NE__BOOL__STRING__STRING, != ) /* Overloaded function */ + + + + + + +/*********************************************/ +/*********************************************/ +/* 2.5.1.5.5 Character string Functions */ +/*********************************************/ +/*********************************************/ + +/*************************************/ +/*** Table 29 ***/ +/*** Character string Functions ***/ +/*************************************/ + +/* We do not delcare explcitly typed versions of the functions in table 29. + * See note above regarding explicitly typed functions for more details. + */ + + +#define __STR_CMP(str1, str2) memcmp((char*)&str1.body,(char*)&str2.body, str1.len < str2.len ? str1.len : str2.len) + + + /***************/ + /* LEN */ + /***************/ +static inline __strlen_t __len(STRING IN) {return IN.len;} + +/* A function, with 1 input paramter, implementing a generic OPERATION */ +#define __genoper_1p_(fname,ret_TYPENAME, par_TYPENAME, OPERATION) \ +static inline ret_TYPENAME fname(EN_ENO_PARAMS, par_TYPENAME par1){\ + TEST_EN(ret_TYPENAME)\ + return (ret_TYPENAME)OPERATION(par1);\ +} + +#define __iec_(TYPENAME) __genoper_1p_(LEN__##TYPENAME##__STRING, TYPENAME, STRING, __len) +__ANY_INT(__iec_) +#undef __iec_ + + + /****************/ + /* LEFT */ + /****************/ + +static inline STRING __left(STRING IN, __strlen_t L){ + STRING res; + res = __INIT_STRING; + L = L < IN.len ? L : IN.len; + memcpy(&res.body, &IN.body, L); + res.len = L; + return res; +} + +#define __iec_(TYPENAME) \ +static inline STRING LEFT__STRING__STRING__##TYPENAME(EN_ENO_PARAMS, STRING str, TYPENAME L){\ + TEST_EN_COND(STRING, L < 0)\ + return (STRING)__left(str,L);\ +} +__ANY_INT(__iec_) +#undef __iec_ + + + /*****************/ + /* RIGHT */ + /*****************/ + +static inline STRING __right(STRING IN, __strlen_t L){ + STRING res; + res = __INIT_STRING; + L = L < IN.len ? L : IN.len; + memcpy(&res.body, &IN.body[IN.len - L], L); + res.len = L; + return res; +} + + +#define __iec_(TYPENAME) \ +static inline STRING RIGHT__STRING__STRING__##TYPENAME(EN_ENO_PARAMS, STRING str, TYPENAME L){\ + TEST_EN_COND(STRING, L < 0)\ + return (STRING)__right(str,L);\ +} +__ANY_INT(__iec_) +#undef __iec_ + + + /***************/ + /* MID */ + /***************/ + +static inline STRING __mid(STRING IN, __strlen_t L, __strlen_t P){ + STRING res; + res = __INIT_STRING; + if(P <= IN.len){ + P -= 1; /* now can be used as [index]*/ + L = L + P <= IN.len ? L : IN.len - P; + memcpy(&res.body, &IN.body[P] , L); + res.len = L; + } + return res; +} + +#define __iec_(TYPENAME) \ +static inline STRING MID__STRING__STRING__##TYPENAME##__##TYPENAME(EN_ENO_PARAMS, STRING str, TYPENAME L, TYPENAME P){\ + TEST_EN_COND(STRING, L < 0 || P < 0)\ + return (STRING)__mid(str,L,P);\ +} +__ANY_INT(__iec_) +#undef __iec_ + + + /******************/ + /* CONCAT */ + /******************/ + +static inline STRING CONCAT__STRING__STRING(UINT param_count, ...){ + UINT i; + STRING res; + va_list ap; + __strlen_t charcount; + charcount = 0; + res = __INIT_STRING; + + va_start (ap, param_count); /* Initialize the argument list. */ + + for (i = 0; i < param_count && charcount < STR_MAX_LEN; i++) + { + STRING tmp = va_arg(ap, STRING); + __strlen_t charrem = STR_MAX_LEN - charcount; + __strlen_t to_write = tmp.len > charrem ? charrem : tmp.len; + memcpy(&res.body[charcount], &tmp.body , to_write); + charcount += to_write; + } + + res.len = charcount; + + va_end (ap); /* Clean up. */ + return res; +} + + /******************/ + /* INSERT */ + /******************/ + +static inline STRING __insert(STRING IN1, STRING IN2, __strlen_t P){ + STRING res; + __strlen_t to_copy; + res = __INIT_STRING; + + to_copy = P > IN1.len ? IN1.len : P; + memcpy(&res.body, &IN1.body , to_copy); + P = res.len = to_copy; + + to_copy = IN2.len + res.len > STR_MAX_LEN ? STR_MAX_LEN - res.len : IN2.len; + memcpy(&res.body[res.len], &IN2.body , to_copy); + res.len += to_copy; + + to_copy = IN1.len - P < STR_MAX_LEN - res.len ? IN1.len - P : STR_MAX_LEN - res.len ; + memcpy(&res.body[res.len], &IN1.body[P] , to_copy); + res.len += to_copy; + + return res; +} + +#define __iec_(TYPENAME) \ +static inline STRING INSERT__STRING__STRING__STRING__##TYPENAME(EN_ENO_PARAMS, STRING str1, STRING str2, TYPENAME P){\ + TEST_EN_COND(STRING, P < 0)\ + return (STRING)__insert(str1,str2,P);\ +} +__ANY_INT(__iec_) +#undef __iec_ + + + /******************/ + /* DELETE */ + /******************/ + +static inline STRING __delete(STRING IN, __strlen_t L, __strlen_t P){ + STRING res; + __strlen_t to_copy; + res = __INIT_STRING; + + to_copy = P > IN.len ? IN.len : P-1; + memcpy(&res.body, &IN.body , to_copy); + P = res.len = to_copy; + + if( IN.len > P + L ){ + to_copy = IN.len - P - L; + memcpy(&res.body[res.len], &IN.body[P + L], to_copy); + res.len += to_copy; + } + + return res; +} + +#define __iec_(TYPENAME) \ +static inline STRING DELETE__STRING__STRING__##TYPENAME##__##TYPENAME(EN_ENO_PARAMS, STRING str, TYPENAME L, TYPENAME P){\ + TEST_EN_COND(STRING, L < 0 || P < 0)\ + return (STRING)__delete(str,L,P);\ +} +__ANY_INT(__iec_) +#undef __iec_ + + + /*******************/ + /* REPLACE */ + /*******************/ + +static inline STRING __replace(STRING IN1, STRING IN2, __strlen_t L, __strlen_t P){ + STRING res; + __strlen_t to_copy; + res = __INIT_STRING; + + to_copy = P > IN1.len ? IN1.len : P-1; + memcpy(&res.body, &IN1.body , to_copy); + P = res.len = to_copy; + + to_copy = IN2.len < L ? IN2.len : L; + + if( to_copy + res.len > STR_MAX_LEN ) + to_copy = STR_MAX_LEN - res.len; + + memcpy(&res.body[res.len], &IN2.body , to_copy); + res.len += to_copy; + + P += L; + if( res.len < STR_MAX_LEN && P < IN1.len) + { + to_copy = IN1.len - P; + memcpy(&res.body[res.len], &IN1.body[P] , to_copy); + res.len += to_copy; + } + + return res; +} + +#define __iec_(TYPENAME) \ +static inline STRING REPLACE__STRING__STRING__STRING__##TYPENAME##__##TYPENAME(EN_ENO_PARAMS, STRING str1, STRING str2, TYPENAME L, TYPENAME P){\ + TEST_EN_COND(STRING, L < 0 || P < 0)\ + return (STRING)__replace(str1,str2,L,P);\ +} +__ANY_INT(__iec_) +#undef __iec_ + + /****************/ + /* FIND */ + /****************/ + +static inline __strlen_t __pfind(STRING* IN1, STRING* IN2){ + UINT count1 = 0; /* offset of first matching char in IN1 */ + UINT count2 = 0; /* count of matching char */ + while(count1 + count2 < IN1->len && count2 < IN2->len) + { + if(IN1->body[count1 + count2] != IN2->body[count2]){ + count1 += count2 + 1; + count2 = 0; + } + else { + count2++; + } + } + return count2 == IN2->len -1 ? 0 : count1 + 1; +} + +#define __iec_(TYPENAME) \ +static inline TYPENAME FIND__##TYPENAME##__STRING__STRING(EN_ENO_PARAMS, STRING str1, STRING str2){\ + TEST_EN(TYPENAME)\ + return (TYPENAME)__pfind(&str1,&str2);\ +} +__ANY_INT(__iec_) +#undef __iec_ + + +/*********************************************/ +/*********************************************/ +/* 2.5.1.5.6 Functions of time data types */ +/*********************************************/ +/*********************************************/ + +/**************************************/ +/*** Table 30 ***/ +/*** Functions of time data types ***/ +/**************************************/ + + +static inline TIME ADD_TIME(EN_ENO_PARAMS, TIME IN1, TIME IN2){ + TEST_EN(TIME) + return __time_add(IN1, IN2); +} + +static inline TOD ADD_TOD_TIME(EN_ENO_PARAMS, TOD IN1, TIME IN2){ + TEST_EN(TOD) + return __time_add(IN1, IN2); +} + +static inline DT ADD_DT_TIME(EN_ENO_PARAMS, DT IN1, TIME IN2){ + TEST_EN(DT) + return __time_add(IN1, IN2); +} + +static inline TIME SUB_TIME(EN_ENO_PARAMS, TIME IN1, TIME IN2){ + TEST_EN(TIME) + return __time_sub(IN1, IN2); +} + +static inline TIME SUB_DATE_DATE(EN_ENO_PARAMS, DATE IN1, DATE IN2){ + TEST_EN(TIME) + return __time_sub(IN1, IN2); +} + +static inline TOD SUB_TOD_TIME(EN_ENO_PARAMS, TOD IN1, TIME IN2){ + TEST_EN(TOD) + return __time_sub(IN1, IN2); +} + +static inline TIME SUB_TOD_TOD(EN_ENO_PARAMS, TOD IN1, TOD IN2){ + TEST_EN(TIME) + return __time_sub(IN1, IN2); +} + +static inline DT SUB_DT_TIME(EN_ENO_PARAMS, DT IN1, TIME IN2){ + TEST_EN(DT) + return __time_sub(IN1, IN2); +} + +static inline TIME SUB_DT_DT(EN_ENO_PARAMS, DT IN1, DT IN2){ + TEST_EN(TIME) + return __time_sub(IN1, IN2); +} + + +/*** MULTIME ***/ +#define __iec_(TYPENAME)\ +static inline TIME MULTIME__TIME__TIME__##TYPENAME(EN_ENO_PARAMS, TIME IN1, TYPENAME IN2){\ + TEST_EN(TIME)\ + return __time_mul(IN1, IN2);\ +} +__ANY_NUM(__iec_) +#undef __iec_ + +/*** MUL ***/ +#define __iec_(TYPENAME)\ +static inline TIME MUL__TIME__TIME__##TYPENAME(EN_ENO_PARAMS, TIME IN1, TYPENAME IN2){\ + TEST_EN(TIME)\ + return __time_mul(IN1, IN2);\ +} +__ANY_NUM(__iec_) +#undef __iec_ + +/*** DIVTIME ***/ +#define __iec_(TYPENAME)\ +static inline TIME DIVTIME__TIME__TIME__##TYPENAME(EN_ENO_PARAMS, TIME IN1, TYPENAME IN2){\ + TEST_EN(TIME)\ + return __time_div(IN1, IN2);\ +} +__ANY_NUM(__iec_) +#undef __iec_ + +/*** DIV ***/ +#define __iec_(TYPENAME)\ +static inline TIME DIV__TIME__TIME__##TYPENAME(EN_ENO_PARAMS, TIME IN1, TYPENAME IN2){\ + TEST_EN(TIME)\ + return __time_div(IN1, IN2);\ +} +__ANY_NUM(__iec_) +#undef __iec_ + +/*** CONCAT_DATE_TOD ***/ +static inline DT CONCAT_DATE_TOD(EN_ENO_PARAMS, DATE IN1, TOD IN2){ + TEST_EN(DT) + return __time_add(IN1, IN2); +} + + + +/****************************************************/ +/****************************************************/ +/* 2.5.1.5.6 Functions of enumerated data types */ +/****************************************************/ +/****************************************************/ + +/********************************************/ +/*** Table 31 ***/ +/*** Functions of enumerated data types ***/ +/********************************************/ + +/* Do we support this? */ diff -r ba80c3ceb6fb -r 2c3c4dc34979 lib/iec_types_all.h --- a/lib/iec_types_all.h Mon Jul 11 09:47:27 2011 +0100 +++ b/lib/iec_types_all.h Fri Jul 29 16:03:28 2011 +0100 @@ -1,7 +1,59 @@ +/* + * Copyright (C) 2007-2011: Edouard TISSERANT and Laurent BESSARD + * + * See COPYING and COPYING.LESSER files for copyright details. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + */ + #ifndef IEC_TYPES_ALL_H #define IEC_TYPES_ALL_H -#include "iec_std_lib_generated.h" + +/* Macro that expand to subtypes */ +#define __ANY(DO) __ANY_DERIVED(DO) __ANY_ELEMENTARY(DO) +#define __ANY_DERIVED(DO) +#define __ANY_ELEMENTARY(DO) __ANY_MAGNITUDE(DO) __ANY_BIT(DO) __ANY_STRING(DO) __ANY_DATE(DO) +#define __ANY_MAGNITUDE(DO) __ANY_NUM(DO) DO(TIME) +#define __ANY_BIT(DO) __ANY_NBIT(DO) DO(BOOL) +#define __ANY_NBIT(DO) DO(BYTE) DO(WORD) DO(DWORD) DO(LWORD) +#define __ANY_STRING(DO) DO(STRING) +#define __ANY_DATE(DO) DO(DATE) DO(TOD) DO(DT) +#define __ANY_NUM(DO) __ANY_REAL(DO) __ANY_INT(DO) +#define __ANY_REAL(DO) DO(REAL) DO(LREAL) +#define __ANY_INT(DO) __ANY_SINT(DO) __ANY_UINT(DO) +#define __ANY_SINT(DO) DO(SINT) DO(INT) DO(DINT) DO(LINT) +#define __ANY_UINT(DO) DO(USINT) DO(UINT) DO(UDINT) DO(ULINT) + + +/* Macro that expand to subtypes */ +#define __ANY_1(DO,P1) __ANY_DERIVED_1(DO,P1) __ANY_ELEMENTARY_1(DO,P1) +#define __ANY_DERIVED_1(DO,P1) +#define __ANY_ELEMENTARY_1(DO,P1) __ANY_MAGNITUDE_1(DO,P1) __ANY_BIT_1(DO,P1) __ANY_STRING_1(DO,P1) __ANY_DATE_1(DO,P1) +#define __ANY_MAGNITUDE_1(DO,P1) __ANY_NUM_1(DO,P1) DO(TIME,P1) +#define __ANY_BIT_1(DO,P1) __ANY_NBIT_1(DO,P1) DO(BOOL,P1) +#define __ANY_NBIT_1(DO,P1) DO(BYTE,P1) DO(WORD,P1) DO(DWORD,P1) DO(LWORD,P1) +#define __ANY_STRING_1(DO,P1) DO(STRING,P1) +#define __ANY_DATE_1(DO,P1) DO(DATE,P1) DO(TOD,P1) DO(DT,P1) +#define __ANY_NUM_1(DO,P1) __ANY_REAL_1(DO,P1) __ANY_INT_1(DO,P1) +#define __ANY_REAL_1(DO,P1) DO(REAL,P1) DO(LREAL,P1) +#define __ANY_INT_1(DO,P1) __ANY_SINT_1(DO,P1) __ANY_UINT_1(DO,P1) +#define __ANY_SINT_1(DO,P1) DO(SINT,P1) DO(INT,P1) DO(DINT,P1) DO(LINT,P1) +#define __ANY_UINT_1(DO,P1) DO(USINT,P1) DO(UINT,P1) DO(UDINT,P1) DO(ULINT,P1) + + /*********************/ /* IEC Types defs */ @@ -67,7 +119,7 @@ /* Those typdefs clash with windows.h */ /* i.e. this file cannot be included aside windows.h */ -ANY(__DECLARE_IEC_TYPE) +__ANY(__DECLARE_IEC_TYPE) typedef struct { __IEC_BOOL_t state; // current step state. 0 : inative, 1: active @@ -85,16 +137,16 @@ } ACTION; /* Extra debug types for SFC */ -#define ANY_SFC(DO) DO(STEP) DO(TRANSITION) DO(ACTION) +#define __ANY_SFC(DO) DO(STEP) DO(TRANSITION) DO(ACTION) /* Enumerate native types */ #define __decl_enum_type(TYPENAME) TYPENAME##_ENUM, #define __decl_enum_pointer(TYPENAME) TYPENAME##_P_ENUM, #define __decl_enum_output(TYPENAME) TYPENAME##_O_ENUM, typedef enum{ - ANY(__decl_enum_type) - ANY(__decl_enum_pointer) - ANY(__decl_enum_output) + __ANY(__decl_enum_type) + __ANY(__decl_enum_pointer) + __ANY(__decl_enum_output) /* SFC specific types are never external or global */ UNKNOWN_ENUM } __IEC_types_enum; @@ -107,7 +159,7 @@ return sizeof(TYPENAME); static inline USINT __get_type_enum_size(__IEC_types_enum t){ switch(t){ - ANY(__decl_size_case) + __ANY(__decl_size_case) /* size do not correspond to real struct. * only a bool is used to represent state*/ default: diff -r ba80c3ceb6fb -r 2c3c4dc34979 lib/ieclib.txt --- a/lib/ieclib.txt Mon Jul 11 09:47:27 2011 +0100 +++ b/lib/ieclib.txt Fri Jul 29 16:03:28 2011 +0100 @@ -39,6 +39,6 @@ {#include "pid_st.txt" } {#include "ramp_st.txt" } -(* From later versions of the standard *) +(* Not in the standard, but useful nonetheless. *) {#include "sema.txt" } diff -r ba80c3ceb6fb -r 2c3c4dc34979 main.cc --- a/main.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/main.cc Fri Jul 29 16:03:28 2011 +0100 @@ -75,10 +75,13 @@ /* A macro for printing out internal parser errors... */ #include // required for std::cerr -#define ERROR error_exit(__FILE__,__LINE__) + + +#define ERROR error_exit(__FILE__,__LINE__) void error_exit(const char *file_name, int line_no) { - std::cerr << "\nInternal program error in file " << file_name - << " at line " << line_no << "\n\n\n"; + std::cerr << "\nInternal compiler error in file " << file_name + << " at line " << line_no << "\n"; +// if (msg != NULL) std::cerr << message << "\n\n"; exit(EXIT_FAILURE); } diff -r ba80c3ceb6fb -r 2c3c4dc34979 stage1_2/iec.flex --- a/stage1_2/iec.flex Mon Jul 11 09:47:27 2011 +0100 +++ b/stage1_2/iec.flex Fri Jul 29 16:03:28 2011 +0100 @@ -814,9 +814,9 @@ fprintf(stderr, "Includes nested too deeply\n"); exit( 1 ); } - include_stack[include_stack_ptr].buffer_state = YY_CURRENT_BUFFER; - include_stack[include_stack_ptr].env = current_tracking; - include_stack[include_stack_ptr].filename = current_filename; + include_stack[include_stack_ptr].buffer_state = YY_CURRENT_BUFFER; + include_stack[include_stack_ptr].env = current_tracking; + include_stack[include_stack_ptr].filename = current_filename; for (i = 0, yyin = NULL; (INCLUDE_DIRECTORIES[i] != NULL) && (yyin == NULL); i++) { char *full_name = strdup3(INCLUDE_DIRECTORIES[i], "/", yytext); diff -r ba80c3ceb6fb -r 2c3c4dc34979 stage1_2/iec.y --- a/stage1_2/iec.y Mon Jul 11 09:47:27 2011 +0100 +++ b/stage1_2/iec.y Fri Jul 29 16:03:28 2011 +0100 @@ -182,6 +182,14 @@ */ extern bool allow_function_overloading; +/* A flag to tell the compiler whether to allow the declaration + * of extensible function (i.e. functions that may have a variable number of + * input parameters, such as AND(word#33, word#44, word#55, word#66). + * This is an extension to the standard syntax. + * See comments below for details why we support this! + */ +extern bool allow_extensible_function_parameters; + /* A global flag used to tell the parser whether to include the full variable location * when printing out error messages... */ @@ -3587,15 +3595,48 @@ ; +/* NOTE: + * The syntax + * variable_name DOTDOT + * is an extension to the standard!!! + * + * In order to be able to handle extensible standard functions + * (i.e. standard functions that may have a variable number of + * input parameters, such as AND(word#33, word#44, word#55, word#66), + * we have extended the acceptable syntax to allow var_name '..' + * in an input variable declaration. + * + * This allows us to parse the declaration of standard + * extensible functions and load their interface definition + * into the abstract syntax tree just like we do to other + * user defined functions. + * This has the advantage that we can later do semantic + * checking of calls to functions (be it a standard or user defined + * function) in (almost) exactly the same way. + * + * Of course, we have a flag that disables this syntax when parsing user + * written code, so we only allow this extra syntax while parsing the + * 'header' file that declares all the standard IEC 61131-3 functions. + */ var1_list: variable_name {$$ = new var1_list_c(locloc(@$)); $$->add_element($1); variable_name_symtable.insert($1, prev_declared_variable_name_token); } +| variable_name integer DOTDOT + {$$ = new var1_list_c(locloc(@$)); $$->add_element(new extensible_input_parameter_c($1, $2, locloc(@$))); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + if (!allow_extensible_function_parameters) print_err_msg(locf(@1), locl(@2), "invalid syntax in variable name declaration."); + } | var1_list ',' variable_name {$$ = $1; $$->add_element($3); variable_name_symtable.insert($3, prev_declared_variable_name_token); } + | var1_list ',' variable_name integer DOTDOT + {$$ = $1; $$->add_element(new extensible_input_parameter_c($3, $4, locloc(@$))); + variable_name_symtable.insert($3, prev_declared_variable_name_token); + if (!allow_extensible_function_parameters) print_err_msg(locf(@1), locl(@2), "invalid syntax in variable name declaration."); + } /* ERROR_CHECK_BEGIN */ | var1_list variable_name {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in variable list."); yynerrs++;} @@ -4307,13 +4348,13 @@ {$$ = new single_byte_string_spec_c(NULL, NULL);} */ STRING '[' integer ']' - {$$ = new single_byte_string_spec_c($3, NULL, locloc(@$));} + {$$ = new single_byte_string_spec_c(new single_byte_limited_len_string_spec_c(new string_type_name_c(locloc(@1)), $3, locloc(@$)), NULL, locloc(@$));} /* | STRING ASSIGN single_byte_character_string - {$$ = new single_byte_string_spec_c(NULL, $3, locloc(@$));} + {$$ = new single_byte_string_spec_c($1, NULL, $3, locloc(@$));} */ | STRING '[' integer ']' ASSIGN single_byte_character_string - {$$ = new single_byte_string_spec_c($3, $6, locloc(@$));} + {$$ = new single_byte_string_spec_c(new single_byte_limited_len_string_spec_c(new string_type_name_c(locloc(@1)), $3, locloc(@$)), $6, locloc(@$));} /* ERROR_CHECK_BEGIN */ | STRING '[' error ']' {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited string type specification."); yyerrok;} @@ -4348,16 +4389,17 @@ double_byte_string_spec: /* WSTRING - {$$ = new double_byte_string_spec_c(NULL, NULL, locloc(@$));} + {$$ = new double_byte_string_spec_c($1, NULL, NULL, locloc(@$));} */ WSTRING '[' integer ']' - {$$ = new double_byte_string_spec_c($3, NULL, locloc(@$));} + {$$ = new double_byte_string_spec_c(new double_byte_limited_len_string_spec_c(new wstring_type_name_c(locloc(@1)), $3, locloc(@$)), NULL, locloc(@$));} + /* | WSTRING ASSIGN double_byte_character_string - {$$ = new double_byte_string_spec_c(NULL, $3, locloc(@$));} + {$$ = new double_byte_string_spec_c($1, NULL, $3, locloc(@$));} */ | WSTRING '[' integer ']' ASSIGN double_byte_character_string - {$$ = new double_byte_string_spec_c($3, $6, locloc(@$));} + {$$ = new double_byte_string_spec_c(new double_byte_limited_len_string_spec_c(new wstring_type_name_c(locloc(@1)), $3, locloc(@$)), $6, locloc(@$));} /* ERROR_CHECK_BEGIN */ | WSTRING '[' error ']' {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited double byte string type specification."); yyerrok;} @@ -4458,27 +4500,18 @@ /* helper symbol for var_spec */ -/* NOTE: The constructs - * - * STRING - * and - * WSTRING - * - * were removed as they are already contained - * within a simple_specification. - */ string_spec: /* STRING - {$$ = new single_byte_string_spec_c(NULL, NULL, locloc(@$));} + {$$ = new single_byte_limited_len_string_spec_c($1, NULL, locloc(@$));} */ STRING '[' integer ']' - {$$ = new single_byte_string_spec_c($3, NULL, locloc(@$));} + {$$ = new single_byte_limited_len_string_spec_c(new string_type_name_c(locloc(@1)), $3, locloc(@$));} /* | WSTRING - {$$ = new double_byte_string_spec_c(NULL, NULL, locloc(@$));} + {$$ = new double_byte_limited_len_string_spec_c($1, NULL, locloc(@$));} */ | WSTRING '[' integer ']' - {$$ = new double_byte_string_spec_c($3, NULL, locloc(@$));} + {$$ = new double_byte_limited_len_string_spec_c(new wstring_type_name_c(locloc(@1)), $3, locloc(@$));} ; @@ -4665,11 +4698,31 @@ identifier | prev_declared_derived_function_name {$$ = $1; - if (not(allow_function_overloading)) { + if (!allow_function_overloading) { fprintf(stderr, "Function overloading not allowed. Invalid identifier %s\n", ((token_c *)($1))->value); ERROR; } } +| AND + {$$ = new identifier_c("AND", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"AND\" not allowed. Invalid identifier\n"); + } +| OR + {$$ = new identifier_c("OR", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"OR\" not allowed. Invalid identifier\n"); + } +| XOR + {$$ = new identifier_c("XOR", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"XOR\" not allowed. Invalid identifier\n"); + } +| NOT + {$$ = new identifier_c("NOT", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"NOT\" not allowed. Invalid identifier\n"); + } +| MOD + {$$ = new identifier_c("MOD", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"MOD\" not allowed. Invalid identifier\n"); + } ; @@ -7901,6 +7954,28 @@ */ bool allow_function_overloading = false; +/* | [var1_list ','] variable_name '..' */ +/* NOTE: This is an extension to the standard!!! */ +/* In order to be able to handle extensible standard functions + * (i.e. standard functions that may have a variable number of + * input parameters, such as AND(word#33, word#44, word#55, word#66), + * we have extended the acceptable syntax to allow var_name '..' + * in an input variable declaration. + * + * This allows us to parse the declaration of standard + * extensible functions and load their interface definition + * into the abstract syntax tree just like we do to other + * user defined functions. + * This has the advantage that we can later do semantic + * checking of calls to functions (be it a standard or user defined + * function) in (almost) exactly the same way. + * + * Of course, we have a flag that disables this syntax when parsing user + * written code, so we only allow this extra syntax while parsing the + * 'header' file that declares all the standard IEC 61131-3 functions. + */ +bool allow_extensible_function_parameters = false; + /* A global flag used to tell the parser whether to include the full variable location * when printing out error messages... */ @@ -7991,6 +8066,22 @@ +/* If function overloading is on, we allow several functions with the same name. + * + * However, to support standard functions, we also allow functions named + * AND, MOD, NOT, OR, XOR, ADD, ... + */ +/* +identifier_c *token_2_identifier_c(char *value, ) { + identifier_c tmp = new identifier_c(value, locloc(@$)); + if (!allow_function_overloading) { + fprintf(stderr, "Function overloading not allowed. Invalid identifier %s\n", ((token_c *)($$))->value); + ERROR; + } + } +} +*/ + /* convert between an il_operator to a function name */ /* This a kludge! * It is required because our language requires more than one @@ -8124,11 +8215,6 @@ FILE *in_file = NULL, *lib_file = NULL; char *libfilename = NULL; - for(int i = 0; standard_function_names[i] != NULL; i++) - if (library_element_symtable.find_value(standard_function_names[i]) == - library_element_symtable.end_value()) - library_element_symtable.insert(standard_function_names[i], standard_function_name_token); - if((in_file = fopen(filename, "r")) == NULL) { char *errmsg = strdup2("Error opening main file ", filename); perror(errmsg); @@ -8165,6 +8251,7 @@ */ yyin = lib_file; allow_function_overloading = true; + allow_extensible_function_parameters = true; full_token_loc = full_token_loc_; current_filename = libfilename; current_tracking = GetNewTracking(yyin); @@ -8193,6 +8280,7 @@ #endif yyin = in_file; allow_function_overloading = false; + allow_extensible_function_parameters = false; full_token_loc = full_token_loc_; current_filename = filename; current_tracking = GetNewTracking(yyin); diff -r ba80c3ceb6fb -r 2c3c4dc34979 stage3/visit_expression_type.cc --- a/stage3/visit_expression_type.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/stage3/visit_expression_type.cc Fri Jul 29 16:03:28 2011 +0100 @@ -604,7 +604,7 @@ } - +#if 0 #define is_num_type is_ANY_NUM_compatible #define is_integer_type is_ANY_INT_compatible #define is_real_type is_ANY_REAL_compatible @@ -633,7 +633,7 @@ #undef is_nbinary_type #undef is_integer_type #undef is_num_type - +#endif @@ -720,12 +720,20 @@ /* A helper function... */ /* check the semantics of a FB or Function non-formal call */ /* e.g. foo(1, 2, 3, 4); */ -void visit_expression_type_c::check_nonformal_call(symbol_c *f_call, symbol_c *f_decl, bool use_il_defvar) { +/* If error_count pointer is != NULL, we do not really print out the errors, + * but rather only count how many errors were found. + * This is used to support overloaded functions, where we have to check each possible + * function, one at a time, untill we find a function call without any errors. + */ +void visit_expression_type_c::check_nonformal_call(symbol_c *f_call, symbol_c *f_decl, bool use_il_defvar, int *error_count) { symbol_c *call_param_value, *call_param_type, *param_type; identifier_c *param_name; function_param_iterator_c fp_iterator(f_decl); function_call_param_iterator_c fcp_iterator(f_call); - + int extensible_parameter_highest_index = -1; + + /* reset error counter */ + if (error_count != NULL) *error_count = 0; /* if use_il_defvar, then the first parameter for the call comes from the il_default_variable */ if (use_il_defvar) { /* The first parameter of the function corresponds to the il_default_variable_type of the function call */ @@ -740,20 +748,48 @@ } while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0)); /* If the function does not have any parameters (param_name == NULL) * then we cannot compare its type with the il_default_variable_type. + * + * However, I (Mario) think this is invalid syntax, as it seems to me all functions must + * have at least one parameter. + * However, we will make this semantic verification consider it possible, as later + * versions of the standard may change that syntax. + * So, instead of generating a syntax error message, we simply check whether the call + * is passing any more parameters besides the default variable (the il default variable may be ignored + * in this case, and not consider it as being a parameter being passed to the function). + * If it does, then we have found a semantic error, otherwise the function call is + * correct, and we simply return. */ - if(param_name != NULL) { + if(param_name == NULL) { + if (fcp_iterator.next_nf() != NULL) + STAGE3_ERROR(f_call, f_call, "Too many parameters in function/FB call."); + return; + } else { + /* param_name != NULL */ param_type = fp_iterator.param_type(); - if(!is_valid_assignment(param_type, il_default_variable_type)) - STAGE3_ERROR(f_call, f_call, "In function/FB call, first parameter has invalid data type."); + if(!is_valid_assignment(param_type, il_default_variable_type)) { + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(f_call, f_call, "In function/FB call, first parameter has invalid data type."); + } + } + + /* the fisrt parameter (il_def_variable) is correct */ + if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) { + extensible_parameter_highest_index = fp_iterator.extensible_param_index(); } } // if (use_il_defvar) + + /* Iterating through the non-formal parameters of the function call */ while((call_param_value = fcp_iterator.next_nf()) != NULL) { /* Obtaining the type of the value being passed in the function call */ call_param_type = base_type((symbol_c*)call_param_value->accept(*this)); if (call_param_type == NULL) { - STAGE3_ERROR(call_param_value, call_param_value, "Could not determine data type of value being passed in function/FB call."); + if (error_count != NULL) (*error_count)++; + /* the following error will usually occur when ST code uses an identifier, that could refer to an enumerated constant, + * but was not actually used as a constant in any definitions of an enumerated data type + */ + else STAGE3_ERROR(call_param_value, call_param_value, "Could not determine data type of value being passed in function/FB call."); continue; } @@ -762,17 +798,43 @@ */ do { param_name = fp_iterator.next(); - /* If there is no parameter declared with that name */ - if(param_name == NULL) {STAGE3_ERROR(f_call, f_call, "Too many parameters in function/FB call."); break;} + /* If there is no other parameter declared, then we are passing too many parameters... */ + if(param_name == NULL) { + if (error_count != NULL) (*error_count)++; + /* Note: We don't want to print out the follwoing error message multiple times, so we return instead of continuing with 'break' */ + else STAGE3_ERROR(f_call, f_call, "Too many parameters in function/FB call."); return; + } } while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0)); - if(param_name != NULL) { - /* Get the parameter type */ - param_type = base_type(fp_iterator.param_type()); - /* If the declared parameter and the parameter from the function call do no have the same type */ - if(!is_valid_assignment(param_type, call_param_type)) STAGE3_ERROR(call_param_value, call_param_value, "Type mismatch in function/FB call parameter."); + /* Get the parameter type */ + param_type = base_type(fp_iterator.param_type()); + /* If the declared parameter and the parameter from the function call do not have the same type */ + if(!is_valid_assignment(param_type, call_param_type)) { + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(call_param_value, call_param_value, "Type mismatch in function/FB call parameter."); } - } + + if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) { + extensible_parameter_highest_index = fp_iterator.extensible_param_index(); + } + } + + /* The function call may not have any errors! */ + /* In the case of a call to an extensible function, we store the highest index + * of the extensible parameters this particular call uses, in the symbol_c object + * of the function call itself! + * In calls to non-extensible functions, this value will be set to -1. + * This information is later used in stage4 to correctly generate the + * output code. + */ + int extensible_param_count = -1; + if (extensible_parameter_highest_index >=0) /* if call to extensible function */ + extensible_param_count = 1 + extensible_parameter_highest_index - fp_iterator.first_extensible_param_index(); + il_function_call_c *il_function_call = dynamic_cast(f_call); + function_invocation_c *function_invocation = dynamic_cast(f_call); + if (il_function_call != NULL) il_function_call ->extensible_param_count = extensible_param_count; + else if (function_invocation != NULL) function_invocation->extensible_param_count = extensible_param_count; + // else ERROR; /* this function is also called by Function Blocks, so this is not an error! */ } @@ -814,12 +876,22 @@ /* A helper function... */ /* check the semantics of a FB or Function formal call */ /* e.g. foo(IN1 := 1, OUT1 =>x, EN := true); */ -void visit_expression_type_c::check_formal_call(symbol_c *f_call, symbol_c *f_decl) { +/* If error_count pointer is != NULL, we do not really print out the errors, + * but rather only count how many errors were found. + * This is used to support overloaded functions, where we have to check each possible + * function, one at a time, untill we find a function call without any errors. + */ +void visit_expression_type_c::check_formal_call(symbol_c *f_call, symbol_c *f_decl, int *error_count) { symbol_c *call_param_value, *call_param_type, *call_param_name, *param_type; symbol_c *verify_duplicate_param; identifier_c *param_name; function_param_iterator_c fp_iterator(f_decl); function_call_param_iterator_c fcp_iterator(f_call); + int extensible_parameter_highest_index = -1; + identifier_c *extensible_parameter_name; + + /* reset error counter */ + if (error_count != NULL) *error_count = 0; /* Iterating through the formal parameters of the function call */ while((call_param_name = fcp_iterator.next_f()) != NULL) { @@ -832,13 +904,15 @@ /* Checking if there are duplicated parameter values */ verify_duplicate_param = fcp_iterator.search_f(call_param_name); if(verify_duplicate_param != call_param_value){ - STAGE3_ERROR(call_param_name, verify_duplicate_param, "Duplicated parameter values."); + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(call_param_name, verify_duplicate_param, "Duplicated parameter values."); } /* Obtaining the type of the value being passed in the function call */ call_param_type = (symbol_c*)call_param_value->accept(*this); if (call_param_type == NULL) { - STAGE3_ERROR(call_param_name, call_param_value, "Could not determine data type of value being passed in function/FB call."); + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(call_param_name, call_param_value, "Could not determine data type of value being passed in function/FB call."); /* The data value being passed is possibly any enumerated type value. * We do not yet handle semantic verification of enumerated types. */ @@ -850,14 +924,58 @@ /* Find the corresponding parameter of the function being called */ param_name = fp_iterator.search(call_param_name); if(param_name == NULL) { - STAGE3_ERROR(call_param_name, call_param_name, "Invalid parameter in function/FB call."); + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(call_param_name, call_param_name, "Invalid parameter in function/FB call."); } else { /* Get the parameter type */ param_type = base_type(fp_iterator.param_type()); /* If the declared parameter and the parameter from the function call have the same type */ - if(!is_valid_assignment(param_type, call_param_type)) STAGE3_ERROR(call_param_name, call_param_value, "Type mismatch function/FB call parameter."); + if(!is_valid_assignment(param_type, call_param_type)) { + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(call_param_name, call_param_value, "Type mismatch function/FB call parameter."); + } + if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) { + extensible_parameter_highest_index = fp_iterator.extensible_param_index(); + extensible_parameter_name = param_name; + } } } + + /* In the case of a call to an extensible function, we store the highest index + * of the extensible parameters this particular call uses, in the symbol_c object + * of the function call itself! + * In calls to non-extensible functions, this value will be set to -1. + * This information is later used in stage4 to correctly generate the + * output code. + */ + int extensible_param_count = -1; + if (extensible_parameter_highest_index >=0) /* if call to extensible function */ + extensible_param_count = 1 + extensible_parameter_highest_index - fp_iterator.first_extensible_param_index(); + il_formal_funct_call_c *il_formal_funct_call = dynamic_cast(f_call); + function_invocation_c *function_invocation = dynamic_cast(f_call); + if (il_formal_funct_call != NULL) il_formal_funct_call->extensible_param_count = extensible_param_count; + else if (function_invocation != NULL) function_invocation->extensible_param_count = extensible_param_count; +// else ERROR; /* this function is also called by Function Blocks, so this is not an error! */ + + /* We have iterated through all the formal parameters of the function call, + * and everything seems fine. + * If the function being called in an extensible function, we now check + * whether the extensible paramters in the formal invocation do not skip + * any indexes... + * + * f(in1:=0, in2:=0, in4:=0) --> ERROR!! + */ + if (extensible_parameter_highest_index >=0) { /* if call to extensible function */ + for (int i=fp_iterator.first_extensible_param_index(); i < extensible_parameter_highest_index; i++) { + char tmp[256]; + if (snprintf(tmp, 256, "%s%d", extensible_parameter_name->value, i) >= 256) ERROR; + if (fcp_iterator.search_f(tmp) == NULL) { + /* error in invocation of extensible function */ + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(f_call, f_call, "Missing extensible parameters in call to extensible function."); + } + } + } } @@ -990,58 +1108,51 @@ if (il_error) return NULL; + symbol_c *return_data_type = NULL; + /* First find the declaration of the function being called! */ - function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); - - symbol_c *return_data_type = NULL; - - if (f_decl == function_symtable.end_value()) { - function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name); - if (current_function_type == function_none) ERROR; - /* This code is for the functions that the user did not declare and that are - * part of the IL or ST languagem (built-in functions). - * For now we won't do the semantics analysis for that kind of functions. - */ - /* - return_data_type = (symbol_c *)search_expression_type->compute_standard_function_default(NULL, symbol); - if (NULL == return_data_type) ERROR; - - function_call_param_iterator_c fcp_iterator(symbol); - - int nb_param = 0; - if (symbol->il_param_list != NULL) - nb_param += ((list_c *)symbol->il_param_list)->n; - - identifier_c en_param_name("EN");*/ - /* Get the value from EN param */ - /*symbol_c *EN_param_value = fcp_iterator.search(&en_param_name); - if (EN_param_value == NULL) - EN_param_value = (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c())); - else - nb_param --; - ADD_PARAM_LIST(EN_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_in) - - identifier_c eno_param_name("EN0");*/ - /* Get the value from ENO param */ - /*symbol_c *ENO_param_value = fcp_iterator.search(&eno_param_name); - if (ENO_param_value != NULL) - nb_param --; - ADD_PARAM_LIST(ENO_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out) + function_symtable_t::iterator lower = function_symtable.lower_bound(symbol->function_name); + function_symtable_t::iterator upper = function_symtable.upper_bound(symbol->function_name); + if (lower == function_symtable.end()) ERROR; + + int error_count = 0; + int *error_count_ptr = NULL; + + function_symtable_t::iterator second = lower; + second++; + if (second != upper) + /* This is a call to an overloaded function... */ + error_count_ptr = &error_count; + + for(; lower != upper; lower++) { + function_declaration_c *f_decl = function_symtable.get_value(lower); - #include "st_code_gen.c" - */ - } else { - /* determine the base data type returned by the function being called... */ - return_data_type = base_type(f_decl->type_name); - /* If the following occurs, then we must have some big bug in the syntax parser (stage 2)... */ - if (NULL == return_data_type) ERROR; - - /* check semantics of data passed in the function call... */ - check_nonformal_call(symbol, f_decl, true); - - /* set the new ddata type of the default variable for the following verifications... */ - il_default_variable_type = return_data_type; - } + check_nonformal_call(symbol, f_decl, true, error_count_ptr); + + if (0 == error_count) { + /* Either: + * (i) we have a call to a non-overloaded function (error_cnt_ptr is NULL!, so error_count won't change!) + * (ii) we have a call to an overloaded function, with no errors! + */ + + /* Store the pointer to the declaration of the function being called. + * This data will be used by stage 4 to call the correct function. + * Mostly needed to disambiguate overloaded functions... + * See comments in absyntax.def for more details + */ + symbol->called_function_declaration = f_decl; + /* determine the base data type returned by the function being called... */ + return_data_type = base_type(f_decl->type_name); + /* If the following occurs, then we must have some big bug in the syntax parser (stage 2)... */ + if (NULL == return_data_type) ERROR; + /* set the new data type of the default variable for the following verifications... */ + il_default_variable_type = return_data_type; + return NULL; + } + } + + /* No compatible function was found for this function call */ + STAGE3_ERROR(symbol, symbol, "Call to an overloaded function with invalid parameter type."); return NULL; } @@ -1161,58 +1272,55 @@ if (il_error) return NULL; - function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); - symbol_c *return_data_type = NULL; - - if (f_decl == function_symtable.end_value()) { + function_symtable_t::iterator lower = function_symtable.lower_bound(symbol->function_name); + function_symtable_t::iterator upper = function_symtable.upper_bound(symbol->function_name); + + if (lower == function_symtable.end()) { function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name); if (current_function_type == function_none) ERROR; - - /* This code is for the functions that the user did not declare and that are - * part of the IL or ST languagem (built-in functions). - * For now we won't do the semantics analysis for that kind of functions. - */ - #if 0 - return_data_type = (symbol_c *)search_expression_type->compute_standard_function_default(NULL, symbol); - if (NULL == return_data_type) ERROR; - - function_call_param_iterator_c fcp_iterator(symbol); - - int nb_param = 0; - if (symbol->il_param_list != NULL) - nb_param += ((list_c *)symbol->il_param_list)->n; - - identifier_c en_param_name("EN"); - /* Get the value from EN param */ - symbol_c *EN_param_value = fcp_iterator.search(&en_param_name); - if (EN_param_value == NULL) - EN_param_value = (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c())); - else - nb_param --; - ADD_PARAM_LIST(EN_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_in) - - identifier_c eno_param_name("EN0"); - /* Get the value from ENO param */ - symbol_c *ENO_param_value = fcp_iterator.search(&eno_param_name); - if (ENO_param_value != NULL) - nb_param --; - ADD_PARAM_LIST(ENO_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out) - - #include "st_code_gen.c" - #endif - } else { - /* determine the base data type returned by the function being called... */ - return_data_type = base_type(f_decl->type_name); - /* the following should never occur. If it does, then we have a bug in the syntax parser (stage 2)... */ - if (NULL == return_data_type) ERROR; - + return NULL; + } + + int error_count = 0; + int *error_count_ptr = NULL; + + function_symtable_t::iterator second = lower; + second++; + if (second != upper) + /* This is a call to an overloaded function... */ + error_count_ptr = &error_count; + + for(; lower != upper; lower++) { + function_declaration_c *f_decl = function_symtable.get_value(lower); + /* check semantics of data passed in the function call... */ - check_formal_call(symbol, f_decl); - - /* the data type of the data returned by the function, and stored in the il default variable... */ - il_default_variable_type = return_data_type; - } + check_formal_call(symbol, f_decl, error_count_ptr); + + if (0 == error_count) { + /* Either: + * (i) we have a call to a non-overloaded function (error_cnt_ptr is NULL!, so error_count won't change!) + * (ii) we have a call to an overloaded function, with no errors! + */ + + /* Store the pointer to the declaration of the function being called. + * This data will be used by stage 4 to call the correct function. + * Mostly needed to disambiguate overloaded functions... + * See comments in absyntax.def for more details + */ + symbol->called_function_declaration = f_decl; + /* determine the base data type returned by the function being called... */ + return_data_type = base_type(f_decl->type_name); + /* the following should never occur. If it does, then we have a bug in the syntax parser (stage 2)... */ + if (NULL == return_data_type) ERROR; + /* the data type of the data returned by the function, and stored in the il default variable... */ + il_default_variable_type = return_data_type; + return NULL; + } + } + + /* No compatible function was found for this function call */ + STAGE3_ERROR(symbol, symbol, "Call to an overloaded function with invalid parameter type."); return NULL; } @@ -1961,22 +2069,52 @@ void *visit_expression_type_c::visit(function_invocation_c *symbol) { - function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); - if (f_decl == function_symtable.end_value()) { - /* TODO: the following code is for standard library functions. We do not yet support this... */ - void *res = compute_standard_function_default(symbol); - if (res != NULL) return res; - ERROR; - } - - /* now check the semantics of the function call... */ - /* If the syntax parser is working correctly, exactly one of the - * following two symbols will be NULL, while the other is != NULL. - */ - if (symbol-> formal_param_list != NULL) check_formal_call (symbol, f_decl); - if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, f_decl); - - return base_type(f_decl->type_name); + function_symtable_t::iterator lower = function_symtable.lower_bound(symbol->function_name); + function_symtable_t::iterator upper = function_symtable.upper_bound(symbol->function_name); + if (lower == function_symtable.end()) ERROR; + + function_symtable_t::iterator second = lower; + second++; + if (second == upper) { + /* call to a function that is not overloaded. */ + /* now check the semantics of the function call... */ + /* If the syntax parser is working correctly, exactly one of the + * following two symbols will be NULL, while the other is != NULL. + */ + function_declaration_c *f_decl = function_symtable.get_value(lower); + if (symbol-> formal_param_list != NULL) check_formal_call (symbol, f_decl); + if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, f_decl); + /* Store the pointer to the declaration of the function being called. + * This data will be used by stage 4 to call the correct function. + * Mostly needed to disambiguate overloaded functions... + * See comments in absyntax.def for more details + */ + symbol->called_function_declaration = f_decl; + return base_type(f_decl->type_name); + } + + /* This is a call to an overloaded function... */ + if (debug) printf("visit_expression_type_c::visit(function_invocation_c *symbol): FOUND CALL TO OVERLOADED FUNCTION!!\n"); + for(; lower != upper; lower++) { + if (debug) printf("visit_expression_type_c::visit(function_invocation_c *symbol): FOUND CALL TO OVERLOADED FUNCTION!! iterating...\n"); + int error_count = 0; + function_declaration_c *f_decl = function_symtable.get_value(lower); + if (symbol-> formal_param_list != NULL) check_formal_call (symbol, f_decl, &error_count); + if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, f_decl, false, &error_count); + if (0 == error_count) { + /* Store the pointer to the declaration of the function being called. + * This data will be used by stage 4 to call the correct function. + * Mostly needed to disambiguate overloaded functions... + * See comments in absyntax.def for more details + */ + symbol->called_function_declaration = f_decl; + return base_type(f_decl->type_name); + } + } + + /* No compatible function was found for this function call */ + STAGE3_ERROR(symbol, symbol, "Call to an overloaded function with invalid parameter type."); + return NULL; } /********************/ diff -r ba80c3ceb6fb -r 2c3c4dc34979 stage3/visit_expression_type.hh --- a/stage3/visit_expression_type.hh Mon Jul 11 09:47:27 2011 +0100 +++ b/stage3/visit_expression_type.hh Fri Jul 29 16:03:28 2011 +0100 @@ -190,10 +190,18 @@ void check_il_fbcall(symbol_c *symbol, const char *input_operator); /* check the semantics of a FB or Function non-formal call */ /* e.g. foo(1, 2, 3, 4); */ - void check_nonformal_call(symbol_c *f_call, symbol_c *f_decl, bool use_il_defvar = false); + /* If error_count pointer is NULL, print out error messages. + * If error_count pointer is != NULL, do not print out error messages, but tally up + * how many errors were found. + */ + void check_nonformal_call(symbol_c *f_call, symbol_c *f_decl, bool use_il_defvar = false, int *error_count = NULL); /* check the semantics of a FB or Function formal call */ /* e.g. foo(IN1 := 1, OUT1 =>x, EN := true); */ - void check_formal_call(symbol_c *f_call, symbol_c *f_decl); + /* If error_count pointer is NULL, print out error messages. + * If error_count pointer is != NULL, do not print out error messages, but tally up + * how many errors were found. + */ + void check_formal_call(symbol_c *f_call, symbol_c *f_decl, int *error_count = NULL); void *compute_standard_function_default(function_invocation_c *st_symbol, il_formal_funct_call_c *il_symbol); diff -r ba80c3ceb6fb -r 2c3c4dc34979 stage4/generate_c/generate_c.cc --- a/stage4/generate_c/generate_c.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/stage4/generate_c/generate_c.cc Fri Jul 29 16:03:28 2011 +0100 @@ -158,12 +158,174 @@ /***********************************************************************/ /***********************************************************************/ + +#include "generate_c.hh" + + +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ + +/* A helper class that prints out the identifiers for function calls to overloaded functions */ +/* Given a function declaration of the function being called, it + * will simply print out the returned data type, + * followed by the data types of all input, output, and in_out parameters. + * for e.g.; + * SIN( REAL) : REAL -> prints out -> REAL__REAL + * LEN( STRING) : INT -> prints out -> INT__STRING + * MUL(TIME, INT) : TIME -> prints out -> TIME__TIME__INT + */ +class print_function_parameter_data_types_c: public generate_c_base_c { + private: + symbol_c *current_type; + bool_type_name_c tmp_bool; + + void print_list(symbol_c *var_list, symbol_c *data_type) { + if (data_type != NULL) { + /* print out the data type once for every variable! */ + list_c *list = dynamic_cast(var_list); + if (list == NULL) ERROR; + for (int i=0; i < list->n; i++) { + s4o.print("__"); + data_type->accept(*this); + } + } + } + + public: + print_function_parameter_data_types_c(stage4out_c *s4o_ptr): + generate_c_base_c(s4o_ptr) + {current_type = NULL;} + + /**************************************/ + /* B.1.5 - Program organization units */ + /**************************************/ + /***********************/ + /* B 1.5.1 - Functions */ + /***********************/ + /* FUNCTION derived_function_name ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ + /* | FUNCTION derived_function_name ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ + void *visit(function_declaration_c *symbol) { + symbol->type_name->accept(*this); /* return type */ + symbol->var_declarations_list->accept(*this); + return NULL; + } + + /* already handled by iterator base class (note that generate_c_base_c inherits from iterator_c) */ + //void *visit(var_declarations_list_c *symbol) {// iterate through list} + + /* already handled by iterator base class (note that generate_c_base_c inherits from iterator_c) */ + //void *visit(input_declarations_c *symbol) {// iterate through list} + + /* already handled by iterator base class (note that generate_c_base_c inherits from iterator_c) */ + //void *visit(input_declaration_list_c *symbol) {// iterate through list} + + void *visit(edge_declaration_c *symbol) { + current_type = &tmp_bool; + symbol->var1_list->accept(*this); + current_type = NULL; + return NULL; + } + + /* We do NOT print out EN and ENO parameters! */ + void *visit(en_param_declaration_c *symbol) {return NULL;} + + /* already handled by iterator base class (note that generate_c_base_c inherits from iterator_c) */ + //void *visit(output_declarations_c *symbol) {// iterate through list} + + /* already handled by iterator base class (note that generate_c_base_c inherits from iterator_c) */ + //void *visit(var_init_decl_list_c *symbol) {// iterate through list} + + void *visit(simple_spec_init_c *symbol) { + /* return the data type */ + return symbol->simple_specification; + } + + /* currently we do not support data types defined in the declaration itself */ + /* For now, sugest the user define a TYPE .. END_TYPE */ + /* NOTE: although this class may also sometimes point to a previously_declared_subrange_type_name + * we don't need this for now, so it is easier to just skip it allocation + */ + void *visit(subrange_spec_init_c *symbol) {return NULL;} + + /* currently we do not support data types defined in the declaration itself */ + /* For now, sugest the user define a TYPE .. END_TYPE */ + /* NOTE: although this class may also sometimes point to a previously_declared_enumerated_type_name + * we don't need this for now, so it is easier to just skip it allocation + */ + void *visit(enumerated_spec_init_c *symbol) {return NULL;} + + /* currently we do not support data types defined in the declaration itself */ + /* For now, sugest the user define a TYPE .. END_TYPE */ + /* NOTE: although this class may also sometimes point to a previously_declared_array_type_name + * we don't need this for now, so it is easier to just skip it allocation + */ + void *visit(array_var_init_decl_c *symbol) {return NULL;} + + /* currently we do not support data types defined in the declaration itself */ + /* For now, sugest the user define a TYPE .. END_TYPE */ + /* NOTE: although this class may also sometimes point to a previously_declared_structured_type_name + * we don't need this for now, so it is easier to just skip it allocation + */ + void *visit(structured_var_init_decl_c *symbol) {return NULL;} + + /* We do NOT print out EN and ENO parameters! */ + void *visit(eno_param_declaration_c *symbol) {return NULL;} + + /* already handled by iterator base class (note that generate_c_base_c inherits from iterator_c) */ + //void *visit(input_output_declarations_c *symbol) {// iterate through list} + + /* already handled by iterator base class (note that generate_c_base_c inherits from iterator_c) */ + //void *visit(var_declaration_list_c *symbol) {iterate through list} + + void *visit(fb_name_decl_c *symbol) { + print_list(symbol->fb_name_list, symbol->function_block_type_name); + return NULL; + } + + void *visit(var1_init_decl_c *symbol) { + print_list(symbol->var1_list, (symbol_c *)symbol->spec_init->accept(*this)); + return NULL; + } + + /* currently we do not support data types defined in the declaration itself */ + /* For now, sugest the user define a TYPE .. END_TYPE */ + void *visit(array_var_declaration_c *symbol) {return NULL;} + + void *visit(structured_var_declaration_c *symbol) { + current_type = symbol->structure_type_name; + symbol->var1_list->accept(*this); + current_type = NULL; + return NULL; + } + + /* currently we do not support data types defined in the declaration itself */ + /* For now, sugest the user define a TYPE .. END_TYPE */ + /* Note that this class is used for fixed length strings... + * STRING [ 42 ] + */ + void *visit(single_byte_string_var_declaration_c *symbol) {return NULL;} + + /* currently we do not support data types defined in the declaration itself */ + /* For now, sugest the user define a TYPE .. END_TYPE */ + /* Note that this class is used for fixed length strings... + * WSTRING [ 42 ] + */ + void *visit(double_byte_string_var_declaration_c *symbol) {return NULL;} +}; + + +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ + + #include "generate_c_st.cc" #include "generate_c_il.cc" #include "generate_c_inlinefcall.cc" -#include "generate_c.hh" - /***********************************************************************/ /***********************************************************************/ /***********************************************************************/ diff -r ba80c3ceb6fb -r 2c3c4dc34979 stage4/generate_c/generate_c_il.cc --- a/stage4/generate_c/generate_c_il.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/stage4/generate_c/generate_c_il.cc Fri Jul 29 16:03:28 2011 +0100 @@ -789,102 +789,122 @@ function_call_param_iterator_c function_call_param_iterator(symbol); - function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); - if (f_decl == function_symtable.end_value()) { - function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name); - if (current_function_type == function_none) ERROR; + function_declaration_c *f_decl = (function_declaration_c *)symbol->called_function_declaration; + if (f_decl == NULL) ERROR; + + /* determine the base data type returned by the function being called... */ + search_base_type_c search_base_type; + return_data_type = (symbol_c *)f_decl->type_name->accept(search_base_type); + if (NULL == return_data_type) ERROR; + + function_name = symbol->function_name; + + /* loop through each function parameter, find the value we should pass + * to it, and then output the c equivalent... + */ + function_param_iterator_c fp_iterator(f_decl); + identifier_c *param_name; + /* flag to remember whether we have already used the value stored in the default variable to pass to the first parameter */ + bool used_defvar = false; + /* flag to cirreclty handle calls to extensible standard functions (i.e. functions with variable number of input parameters) */ + bool found_first_extensible_parameter = false; + for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { + if (fp_iterator.is_extensible_param() && (!found_first_extensible_parameter)) { + /* We are calling an extensible function. Before passing the extensible + * parameters, we must add a dummy paramater value to tell the called + * function how many extensible parameters we will be passing. + * + * Note that stage 3 has already determined the number of extensible + * paramters, and stored that info in the abstract syntax tree. We simply + * re-use that value. + */ + /* NOTE: we are not freeing the malloc'd memory. This is not really a bug. + * Since we are writing a compiler, which runs to termination quickly, + * we can consider this as just memory required for the compilation process + * that will be free'd when the program terminates. + */ + char *tmp = (char *)malloc(32); /* enough space for a call with 10^31 (larger than 2^64) input parameters! */ + if (tmp == NULL) ERROR; + int res = snprintf(tmp, 32, "%d", symbol->extensible_param_count); + if ((res >= 32) || (res < 0)) ERROR; + identifier_c *param_value = new identifier_c(tmp); + uint_type_name_c *param_type = new uint_type_name_c(); + identifier_c *param_name = new identifier_c(""); + ADD_PARAM_LIST(param_name, param_value, param_type, function_param_iterator_c::direction_in) + found_first_extensible_parameter = true; + } - return_data_type = (symbol_c *)search_expression_type->compute_standard_function_il(symbol, param_data_type); - if (NULL == return_data_type) ERROR; + symbol_c *param_type = fp_iterator.param_type(); + if (param_type == NULL) ERROR; - symbol_c *en_param_name = (symbol_c *)(new identifier_c("EN")); - /* Add the value from EN param */ - ADD_PARAM_LIST(en_param_name, - (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c())), - (symbol_c*)(new bool_type_name_c()), - function_param_iterator_c::direction_in) + function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); - symbol_c *eno_param_name = (symbol_c *)(new identifier_c("ENO")); - /* Add the value from ENO param */ - ADD_PARAM_LIST(eno_param_name, NULL, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out) + symbol_c *param_value = NULL; + + /* Get the value from a foo( = ) style call */ + /* NOTE: Since the class il_function_call_c only references a non.formal function call, + * the following line of code is not required in this case. However, it doesn't + * harm to leave it in, as in the case of a non-formal syntax function call, + * it will always return NULL. + * We leave it in in case we later decide to merge this part of the code together + * with the function calling code in generate_c_st_c, which does require + * the following line... + */ + if (param_value == NULL) + param_value = function_call_param_iterator.search_f(param_name); + + /* if it is the first parameter in a non-formal function call (which is the + * case being handled!), semantics specifies that we should + * get the value off the IL default variable! + * + * However, if the parameter is an implicitly defined EN or ENO parameter, we should not + * use the default variable as a source of data to pass to those parameters! + */ + if ((param_value == NULL) && (!used_defvar) && !fp_iterator.is_en_eno_param_implicit()) { + param_value = &this->default_variable_name; + used_defvar = true; + } + + /* Get the value from a foo() style call */ + if ((param_value == NULL) && !fp_iterator.is_en_eno_param_implicit()) { + param_value = function_call_param_iterator.next_nf(); + } - int nb_param = 1; - if (symbol->il_operand_list != NULL) - nb_param += ((list_c *)symbol->il_operand_list)->n; - - #include "il_code_gen.c" - - } - else { - /* determine the base data type returned by the function being called... */ - search_base_type_c search_base_type; - return_data_type = (symbol_c *)f_decl->type_name->accept(search_base_type); - if (NULL == return_data_type) ERROR; - - function_name = symbol->function_name; + /* if no more parameter values in function call, and the current parameter + * of the function declaration is an extensible parameter, we + * have reached the end, and should simply jump out of the for loop. + */ + if ((param_value == NULL) && (fp_iterator.is_extensible_param())) { + break; + } - /* loop through each function parameter, find the value we should pass - * to it, and then output the c equivalent... - */ - - function_param_iterator_c fp_iterator(f_decl); - identifier_c *param_name; - for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { - symbol_c *param_type = fp_iterator.param_type(); - if (param_type == NULL) ERROR; - - function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); - - symbol_c *param_value = NULL; - - /* if it is the first parameter, semantics specifies that we should - * get the value off the IL default variable! - */ - if (1 == i) - param_value = &this->default_variable_name; - - /* Get the value from a foo( = ) style call */ - /* NOTE: the following line of code is not required in this case, but it doesn't - * harm to leave it in, as in the case of a non-formal syntax function call, - * it will always return NULL. - * We leave it in in case we later decide to merge this part of the code together - * with the function calling code in generate_c_st_c, which does require - * the following line... - */ - if (param_value == NULL) - param_value = function_call_param_iterator.search_f(param_name); - - /* Get the value from a foo() style call */ - if (param_value == NULL) { - param_value = function_call_param_iterator.next_nf(); - if (param_value != NULL && fp_iterator.is_en_eno_param_implicit()) ERROR; - } - - if (param_value == NULL && param_direction == function_param_iterator_c::direction_in) { - /* No value given for parameter, so we must use the default... */ - /* First check whether default value specified in function declaration...*/ - param_value = fp_iterator.default_value(); - } - - ADD_PARAM_LIST(param_name, param_value, param_type, fp_iterator.param_direction()) - } /* for(...) */ - } - + if ((param_value == NULL) && (param_direction == function_param_iterator_c::direction_in)) { + /* No value given for parameter, so we must use the default... */ + /* First check whether default value specified in function declaration...*/ + param_value = fp_iterator.default_value(); + } + + ADD_PARAM_LIST(param_name, param_value, param_type, fp_iterator.param_direction()) + } /* for(...) */ + if (function_call_param_iterator.next_nf() != NULL) ERROR; bool has_output_params = false; if (!this->is_variable_prefix_null()) { PARAM_LIST_ITERATOR() { - if ((PARAM_DIRECTION == function_param_iterator_c::direction_out || - PARAM_DIRECTION == function_param_iterator_c::direction_inout) && - PARAM_VALUE != NULL) { - if (!has_output_params) { - has_output_params = true; - } - } - } - } + if ((PARAM_DIRECTION == function_param_iterator_c::direction_out || + PARAM_DIRECTION == function_param_iterator_c::direction_inout) && + PARAM_VALUE != NULL) { + has_output_params = true; + } + } + } + + /* Check whether we are calling an overloaded function! */ + /* (fdecl_mutiplicity==2) => calling overloaded function */ + int fdecl_mutiplicity = function_symtable.multiplicity(symbol->function_name); + if (fdecl_mutiplicity == 0) ERROR; default_variable_name.current_type = return_data_type; this->default_variable_name.accept(*this); @@ -897,21 +917,34 @@ s4o.print(")"); } if (function_type_suffix != NULL) { - function_type_suffix = search_expression_type->default_literal_type(function_type_prefix); + function_type_suffix = search_expression_type->default_literal_type(function_type_prefix); } if (has_output_params) { - fcall_number++; - s4o.print("__"); + fcall_number++; + s4o.print("__"); fbname->accept(*this); s4o.print("_"); function_name->accept(*this); + if (fdecl_mutiplicity == 2) { + /* function being called is overloaded! */ + s4o.print("__"); + print_function_parameter_data_types_c overloaded_func_suf(&s4o); + f_decl->accept(overloaded_func_suf); + } s4o.print_integer(fcall_number); } else { - if (function_name != NULL) - function_name->accept(*this); + if (function_name != NULL) { + function_name->accept(*this); + if (fdecl_mutiplicity == 2) { + /* function being called is overloaded! */ + s4o.print("__"); + print_function_parameter_data_types_c overloaded_func_suf(&s4o); + f_decl->accept(overloaded_func_suf); + } + } if (function_type_suffix != NULL) - function_type_suffix->accept(*this); + function_type_suffix->accept(*this); } s4o.print("("); s4o.indent_right(); @@ -923,8 +956,8 @@ switch (PARAM_DIRECTION) { case function_param_iterator_c::direction_in: - if (nb_param > 0) - s4o.print(",\n"+s4o.indent_spaces); + if (nb_param > 0) + s4o.print(",\n"+s4o.indent_spaces); if (param_value == NULL) { /* If not, get the default value of this variable's type */ param_value = (symbol_c *)current_param_type->accept(*type_initial_value_c::instance()); @@ -943,18 +976,18 @@ break; case function_param_iterator_c::direction_out: case function_param_iterator_c::direction_inout: - if (!has_output_params) { + if (!has_output_params) { if (nb_param > 0) - s4o.print(",\n"+s4o.indent_spaces); - if (param_value == NULL) { - s4o.print("NULL"); - } else { - wanted_variablegeneration = fparam_output_vg; - param_value->accept(*this); - wanted_variablegeneration = expression_vg; - } - nb_param++; - } + s4o.print(",\n"+s4o.indent_spaces); + if (param_value == NULL) { + s4o.print("NULL"); + } else { + wanted_variablegeneration = fparam_output_vg; + param_value->accept(*this); + wanted_variablegeneration = expression_vg; + } + nb_param++; + } break; case function_param_iterator_c::direction_extref: /* TODO! */ @@ -964,7 +997,7 @@ } if (has_output_params) { if (nb_param > 0) - s4o.print(",\n"+s4o.indent_spaces); + s4o.print(",\n"+s4o.indent_spaces); s4o.print(FB_FUNCTION_PARAM); } @@ -1072,7 +1105,10 @@ symbol_c *param_value = function_call_param_iterator.search_f(param_name); /* Get the value from a foo() style call */ - if (param_value == NULL) + /* When using the informal invocation style, user can not pass values to EN or ENO parameters if these + * were implicitly defined! + */ + if ((param_value == NULL) && !fp_iterator.is_en_eno_param_implicit()) param_value = function_call_param_iterator.next_nf(); symbol_c *param_type = fp_iterator.param_type(); @@ -1116,7 +1152,10 @@ symbol_c *param_value = function_call_param_iterator.search_f(param_name); /* Get the value from a foo() style call */ - if (param_value == NULL) + /* When using the informal invocation style, user can not pass values to EN or ENO parameters if these + * were implicitly defined! + */ + if ((param_value == NULL) && !fp_iterator.is_en_eno_param_implicit()) param_value = function_call_param_iterator.next_nf(); /* now output the value assignment */ @@ -1158,85 +1197,100 @@ function_call_param_iterator_c function_call_param_iterator(symbol); - function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); - if (f_decl == function_symtable.end_value()) { - function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name); - if (current_function_type == function_none) ERROR; + function_declaration_c *f_decl = (function_declaration_c *)symbol->called_function_declaration; + if (f_decl == NULL) ERROR; + + /* determine the base data type returned by the function being called... */ + search_base_type_c search_base_type; + return_data_type = (symbol_c *)f_decl->type_name->accept(search_base_type); + if (NULL == return_data_type) ERROR; + + function_name = symbol->function_name; + + /* loop through each function parameter, find the value we should pass + * to it, and then output the c equivalent... + */ + function_param_iterator_c fp_iterator(f_decl); + identifier_c *param_name; + + /* flag to cirreclty handle calls to extensible standard functions (i.e. functions with variable number of input parameters) */ + bool found_first_extensible_parameter = false; + for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { + if (fp_iterator.is_extensible_param() && (!found_first_extensible_parameter)) { + /* We are calling an extensible function. Before passing the extensible + * parameters, we must add a dummy paramater value to tell the called + * function how many extensible parameters we will be passing. + * + * Note that stage 3 has already determined the number of extensible + * paramters, and stored that info in the abstract syntax tree. We simply + * re-use that value. + */ + /* NOTE: we are not freeing the malloc'd memory. This is not really a bug. + * Since we are writing a compiler, which runs to termination quickly, + * we can consider this as just memory required for the compilation process + * that will be free'd when the program terminates. + */ + char *tmp = (char *)malloc(32); /* enough space for a call with 10^31 (larger than 2^64) input parameters! */ + if (tmp == NULL) ERROR; + int res = snprintf(tmp, 32, "%d", symbol->extensible_param_count); + if ((res >= 32) || (res < 0)) ERROR; + identifier_c *param_value = new identifier_c(tmp); + uint_type_name_c *param_type = new uint_type_name_c(); + identifier_c *param_name = new identifier_c(""); + ADD_PARAM_LIST(param_name, param_value, param_type, function_param_iterator_c::direction_in) + found_first_extensible_parameter = true; + } - return_data_type = (symbol_c *)search_expression_type->compute_standard_function_default(NULL, symbol); - if (NULL == return_data_type) ERROR; + if (fp_iterator.is_extensible_param()) { + /* since we are handling an extensible parameter, we must add the index to the + * parameter name so we can go looking for the value passed to the correct + * extended parameter (e.g. IN1, IN2, IN3, IN4, ...) + */ + char *tmp = (char *)malloc(32); /* enough space for a call with 10^31 (larger than 2^64) input parameters! */ + int res = snprintf(tmp, 32, "%d", fp_iterator.extensible_param_index()); + if ((res >= 32) || (res < 0)) ERROR; + param_name = new identifier_c(strdup2(param_name->value, tmp)); + if (param_name->value == NULL) ERROR; + } + + symbol_c *param_type = fp_iterator.param_type(); + if (param_type == NULL) ERROR; + + function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); + + symbol_c *param_value = NULL; + + /* Get the value from a foo( = ) style call */ + if (param_value == NULL) + param_value = function_call_param_iterator.search_f(param_name); + + /* Get the value from a foo() style call */ + /* NOTE: the following line of code is not required in this case, but it doesn't + * harm to leave it in, as in the case of a formal syntax function call, + * it will always return NULL. + * We leave it in in case we later decide to merge this part of the code together + * with the function calling code in generate_c_st_c, which does require + * the following line... + */ + if ((param_value == NULL) && !fp_iterator.is_en_eno_param_implicit()) { + param_value = function_call_param_iterator.next_nf(); + } - int nb_param = 0; - if (symbol->il_param_list != NULL) - nb_param += ((list_c *)symbol->il_param_list)->n; + /* if no more parameter values in function call, and the current parameter + * of the function declaration is an extensible parameter, we + * have reached the end, and should simply jump out of the for loop. + */ + if ((param_value == NULL) && (fp_iterator.is_extensible_param())) { + break; + } - symbol_c *en_param_name = (symbol_c *)(new identifier_c("EN")); - /* Get the value from EN param */ - symbol_c *EN_param_value = function_call_param_iterator.search_f(en_param_name); - if (EN_param_value == NULL) - EN_param_value = (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c())); - else - nb_param --; - ADD_PARAM_LIST(en_param_name, EN_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_in) + if ((param_value == NULL) && (param_direction == function_param_iterator_c::direction_in)) { + /* No value given for parameter, so we must use the default... */ + /* First check whether default value specified in function declaration...*/ + param_value = fp_iterator.default_value(); + } - symbol_c *eno_param_name = (symbol_c *)(new identifier_c("ENO")); - /* Get the value from ENO param */ - symbol_c *ENO_param_value = function_call_param_iterator.search_f(eno_param_name); - if (ENO_param_value != NULL) - nb_param --; - ADD_PARAM_LIST(eno_param_name, ENO_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out) - - #include "st_code_gen.c" - - } - else { - /* determine the base data type returned by the function being called... */ - search_base_type_c search_base_type; - return_data_type = (symbol_c *)f_decl->type_name->accept(search_base_type); - if (NULL == return_data_type) ERROR; - - function_name = symbol->function_name; - - /* loop through each function parameter, find the value we should pass - * to it, and then output the c equivalent... - */ - - function_param_iterator_c fp_iterator(f_decl); - identifier_c *param_name; - for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { - symbol_c *param_type = fp_iterator.param_type(); - if (param_type == NULL) ERROR; - - function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); - - - symbol_c *param_value = NULL; - - /* Get the value from a foo( = ) style call */ - if (param_value == NULL) - param_value = function_call_param_iterator.search_f(param_name); - - /* Get the value from a foo() style call */ - /* NOTE: the following line of code is not required in this case, but it doesn't - * harm to leave it in, as in the case of a formal syntax function call, - * it will always return NULL. - * We leave it in in case we later decide to merge this part of the code together - * with the function calling code in generate_c_st_c, which does require - * the following line... - */ - if (param_value == NULL) { - param_value = function_call_param_iterator.next_nf(); - if (param_value != NULL && fp_iterator.is_en_eno_param_implicit()) ERROR; - } - - if (param_value == NULL) { - /* No value given for parameter, so we must use the default... */ - /* First check whether default value specified in function declaration...*/ - param_value = fp_iterator.default_value(); - } - - ADD_PARAM_LIST(param_name, param_value, param_type, fp_iterator.param_direction()) - } + ADD_PARAM_LIST(param_name, param_value, param_type, fp_iterator.param_direction()) } if (function_call_param_iterator.next_nf() != NULL) ERROR; @@ -1245,15 +1299,21 @@ if (!this->is_variable_prefix_null()) { PARAM_LIST_ITERATOR() { - if ((PARAM_DIRECTION == function_param_iterator_c::direction_out || - PARAM_DIRECTION == function_param_iterator_c::direction_inout) && - PARAM_VALUE != NULL) { - if (!has_output_params) { - has_output_params = true; - } - } - } - } + if ((PARAM_DIRECTION == function_param_iterator_c::direction_out || + PARAM_DIRECTION == function_param_iterator_c::direction_inout) && + PARAM_VALUE != NULL) { + has_output_params = true; + } + } + } + + /* Check whether we are calling an overloaded function! */ + /* (fdecl_mutiplicity==2) => calling overloaded function */ + int fdecl_mutiplicity = function_symtable.multiplicity(symbol->function_name); + if (fdecl_mutiplicity == 0) ERROR; + if (fdecl_mutiplicity == 1) + /* function being called is NOT overloaded! */ + f_decl = NULL; default_variable_name.current_type = return_data_type; this->default_variable_name.accept(*this); @@ -1265,19 +1325,32 @@ s4o.print(")"); } if (function_type_suffix != NULL) { - function_type_suffix = search_expression_type->default_literal_type(function_type_prefix); + function_type_suffix = search_expression_type->default_literal_type(function_type_prefix); } if (has_output_params) { - fcall_number++; - s4o.print("__"); + fcall_number++; + s4o.print("__"); fbname->accept(*this); s4o.print("_"); function_name->accept(*this); + if (fdecl_mutiplicity == 2) { + /* function being called is overloaded! */ + s4o.print("__"); + print_function_parameter_data_types_c overloaded_func_suf(&s4o); + f_decl->accept(overloaded_func_suf); + } s4o.print_integer(fcall_number); } else { - if (function_name != NULL) + if (function_name != NULL) { function_name->accept(*this); + if (fdecl_mutiplicity == 2) { + /* function being called is overloaded! */ + s4o.print("__"); + print_function_parameter_data_types_c overloaded_func_suf(&s4o); + f_decl->accept(overloaded_func_suf); + } + } if (function_type_suffix != NULL) function_type_suffix->accept(*this); } @@ -1286,14 +1359,13 @@ int nb_param = 0; PARAM_LIST_ITERATOR() { - symbol_c *param_value = PARAM_VALUE; - current_param_type = PARAM_TYPE; - + symbol_c *param_value = PARAM_VALUE; + current_param_type = PARAM_TYPE; switch (PARAM_DIRECTION) { case function_param_iterator_c::direction_in: - if (nb_param > 0) - s4o.print(",\n"+s4o.indent_spaces); - if (param_value == NULL) { + if (nb_param > 0) + s4o.print(",\n"+s4o.indent_spaces); + if (param_value == NULL) { /* If not, get the default value of this variable's type */ param_value = (symbol_c *)current_param_type->accept(*type_initial_value_c::instance()); } @@ -1307,26 +1379,26 @@ current_param_type->accept(*this); s4o.print(")"); print_check_function(current_param_type, param_value); - nb_param++; + nb_param++; break; case function_param_iterator_c::direction_out: case function_param_iterator_c::direction_inout: - if (!has_output_params) { + if (!has_output_params) { if (nb_param > 0) - s4o.print(",\n"+s4o.indent_spaces); - if (param_value == NULL) { - s4o.print("NULL"); - } else { - wanted_variablegeneration = fparam_output_vg; - param_value->accept(*this); - wanted_variablegeneration = expression_vg; - } - } - break; + s4o.print(",\n"+s4o.indent_spaces); + if (param_value == NULL) { + s4o.print("NULL"); + } else { + wanted_variablegeneration = fparam_output_vg; + param_value->accept(*this); + wanted_variablegeneration = expression_vg; + } + } + break; case function_param_iterator_c::direction_extref: /* TODO! */ ERROR; - break; + break; } /* switch */ } /* for(...) */ if (has_output_params) { @@ -1659,7 +1731,7 @@ void *visit(ADD_operator_c *symbol) { if (search_expression_type->is_time_type(this->default_variable_name.current_type) && search_expression_type->is_time_type(this->current_operand_type)) { - XXX_function("__TIME_ADD", &(this->default_variable_name), this->current_operand); + XXX_function("__time_add", &(this->default_variable_name), this->current_operand); /* the data type resulting from this operation... */ this->default_variable_name.current_type = this->current_operand_type; return NULL; @@ -1679,7 +1751,7 @@ void *visit(SUB_operator_c *symbol) { if (search_expression_type->is_time_type(this->default_variable_name.current_type) && search_expression_type->is_time_type(this->current_operand_type)) { - XXX_function("__TIME_SUB", &(this->default_variable_name), this->current_operand); + XXX_function("__time_sub", &(this->default_variable_name), this->current_operand); /* the data type resulting from this operation... */ this->default_variable_name.current_type = this->current_operand_type; return NULL; @@ -1699,7 +1771,7 @@ void *visit(MUL_operator_c *symbol) { if (search_expression_type->is_time_type(this->default_variable_name.current_type) && search_expression_type->is_integer_type(this->current_operand_type)) { - XXX_function("__TIME_MUL", &(this->default_variable_name), this->current_operand); + XXX_function("__time_mul", &(this->default_variable_name), this->current_operand); /* the data type resulting from this operation... */ return NULL; } @@ -1718,7 +1790,7 @@ void *visit(DIV_operator_c *symbol) { if (search_expression_type->is_time_type(this->default_variable_name.current_type) && search_expression_type->is_integer_type(this->current_operand_type)) { - XXX_function("__TIME_DIV", &(this->default_variable_name), this->current_operand); + XXX_function("__time_div", &(this->default_variable_name), this->current_operand); /* the data type resulting from this operation... */ return NULL; } @@ -1748,7 +1820,7 @@ void *visit(GT_operator_c *symbol) { if (!search_base_type.type_is_enumerated(this->default_variable_name.current_type) && search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) - return CMP_operator(this->current_operand, "__gt_"); + return CMP_operator(this->current_operand, "GT_"); ERROR; return NULL; } @@ -1756,14 +1828,14 @@ void *visit(GE_operator_c *symbol) { if (!search_base_type.type_is_enumerated(this->default_variable_name.current_type) && search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) - return CMP_operator(this->current_operand, "__ge_"); + return CMP_operator(this->current_operand, "GE_"); ERROR; return NULL; } void *visit(EQ_operator_c *symbol) { if (search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) - return CMP_operator(this->current_operand, "__eq_"); + return CMP_operator(this->current_operand, "EQ_"); ERROR; return NULL; } @@ -1771,7 +1843,7 @@ void *visit(LT_operator_c *symbol) { if (!search_base_type.type_is_enumerated(this->default_variable_name.current_type) && search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) - return CMP_operator(this->current_operand, "__lt_"); + return CMP_operator(this->current_operand, "LT_"); ERROR; return NULL; } @@ -1779,14 +1851,14 @@ void *visit(LE_operator_c *symbol) { if (!search_base_type.type_is_enumerated(this->default_variable_name.current_type) && search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) - return CMP_operator(this->current_operand, "__le_"); + return CMP_operator(this->current_operand, "LE_"); ERROR; return NULL; } void *visit(NE_operator_c *symbol) { if (search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) - return CMP_operator(this->current_operand, "__ne_"); + return CMP_operator(this->current_operand, "NE_"); ERROR; return NULL; } diff -r ba80c3ceb6fb -r 2c3c4dc34979 stage4/generate_c/generate_c_inlinefcall.cc --- a/stage4/generate_c/generate_c_inlinefcall.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/stage4/generate_c/generate_c_inlinefcall.cc Fri Jul 29 16:03:28 2011 +0100 @@ -84,10 +84,13 @@ } } + + void generate_inline(symbol_c *function_name, symbol_c *function_type_prefix, symbol_c *function_type_suffix, - std::list param_list) { + std::list param_list, + function_declaration_c *f_decl = NULL) { std::list::iterator pt; fcall_number++; @@ -103,8 +106,13 @@ fbname->accept(*this); s4o.print("_"); function_name->accept(*this); + if (f_decl != NULL) { +printf("generate_inline(): calling print_function_parameter_data_types_c !!!!!!!!!!!!!!!!!!!!!!\n"); + print_function_parameter_data_types_c overloaded_func_suf(&s4o); + f_decl->accept(overloaded_func_suf); + } if (function_type_suffix) { - function_type_suffix->accept(*this); + function_type_suffix->accept(*this); } s4o.print_integer(fcall_number); s4o.print("("); @@ -119,11 +127,11 @@ } } fbname->accept(*this); - s4o.print(" *"); - s4o.print(FB_FUNCTION_PARAM); - s4o.indent_left(); - s4o.print(")\n" + s4o.indent_spaces); - s4o.print("{\n"); + s4o.print(" *"); + s4o.print(FB_FUNCTION_PARAM); + s4o.indent_left(); + s4o.print(")\n" + s4o.indent_spaces); + s4o.print("{\n"); s4o.indent_right(); s4o.print(s4o.indent_spaces); @@ -132,59 +140,63 @@ s4o.print(INLINE_RESULT_TEMP_VAR); s4o.print(";\n"); - PARAM_LIST_ITERATOR() { - if ((PARAM_DIRECTION == function_param_iterator_c::direction_out || - PARAM_DIRECTION == function_param_iterator_c::direction_inout) && - PARAM_VALUE != NULL) { - s4o.print(s4o.indent_spaces); - PARAM_TYPE->accept(*this); + PARAM_LIST_ITERATOR() { + if ((PARAM_DIRECTION == function_param_iterator_c::direction_out || + PARAM_DIRECTION == function_param_iterator_c::direction_inout) && + PARAM_VALUE != NULL) { + s4o.print(s4o.indent_spaces); + PARAM_TYPE->accept(*this); s4o.print(" "); s4o.print(TEMP_VAR); PARAM_NAME->accept(*this); s4o.print(" = "); print_check_function(PARAM_TYPE, PARAM_VALUE); s4o.print(";\n"); - } - } - - s4o.print(s4o.indent_spaces + INLINE_RESULT_TEMP_VAR), - s4o.print(" = "); - function_name->accept(*this); - if (function_type_suffix) + } + } + + s4o.print(s4o.indent_spaces + INLINE_RESULT_TEMP_VAR), + s4o.print(" = "); + function_name->accept(*this); + if (f_decl != NULL) { +printf("generate_inline(): calling print_function_parameter_data_types_c !!!!!!!!!!!!!!!!!!!!!!\n"); + print_function_parameter_data_types_c overloaded_func_suf(&s4o); + f_decl->accept(overloaded_func_suf); + } + + if (function_type_suffix) function_type_suffix->accept(*this); - s4o.print("("); - s4o.indent_right(); - - PARAM_LIST_ITERATOR() { - if (pt != param_list.begin()) - s4o.print(",\n" + s4o.indent_spaces); - if (PARAM_DIRECTION == function_param_iterator_c::direction_in) - PARAM_NAME->accept(*this); - else if (PARAM_VALUE != NULL){ + s4o.print("("); + s4o.indent_right(); + + PARAM_LIST_ITERATOR() { + if (pt != param_list.begin()) + s4o.print(",\n" + s4o.indent_spaces); + if (PARAM_DIRECTION == function_param_iterator_c::direction_in) + PARAM_NAME->accept(*this); + else if (PARAM_VALUE != NULL){ s4o.print("&"); s4o.print(TEMP_VAR); PARAM_NAME->accept(*this); - } - else { - s4o.print("NULL"); - } - } - s4o.print(");\n"); - s4o.indent_left(); - - PARAM_LIST_ITERATOR() { + } else { + s4o.print("NULL"); + } + } + s4o.print(");\n"); + s4o.indent_left(); + + PARAM_LIST_ITERATOR() { if ((PARAM_DIRECTION == function_param_iterator_c::direction_out || - PARAM_DIRECTION == function_param_iterator_c::direction_inout) && - PARAM_VALUE != NULL) { - + PARAM_DIRECTION == function_param_iterator_c::direction_inout) && + PARAM_VALUE != NULL) { s4o.print(s4o.indent_spaces); print_setter(PARAM_VALUE, PARAM_TYPE, PARAM_NAME); s4o.print(";\n"); - } - } - s4o.print(s4o.indent_spaces + "return "); - s4o.print(INLINE_RESULT_TEMP_VAR); - s4o.print(";\n"); + } + } + s4o.print(s4o.indent_spaces + "return "); + s4o.print(INLINE_RESULT_TEMP_VAR); + s4o.print(";\n"); s4o.indent_left(); s4o.print(s4o.indent_spaces + "}\n\n"); @@ -342,7 +354,7 @@ void *visit(il_function_call_c *symbol) { symbol_c* function_type_prefix = NULL; - symbol_c* function_name = NULL; + symbol_c* function_name = NULL; symbol_c* function_type_suffix = NULL; DECLARE_PARAM_LIST() @@ -350,86 +362,104 @@ function_call_param_iterator_c function_call_param_iterator(symbol); - function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); - if (f_decl == function_symtable.end_value()) { - function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name); - if (current_function_type == function_none) ERROR; - - function_type_prefix = (symbol_c *)search_expression_type->compute_standard_function_il(symbol, param_data_type); - - symbol_c *en_param_name = (symbol_c *)(new identifier_c("EN")); - /* Add the value from EN param */ - ADD_PARAM_LIST(en_param_name, - (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c())), - (symbol_c*)(new bool_type_name_c()), - function_param_iterator_c::direction_in) - - symbol_c *eno_param_name = (symbol_c *)(new identifier_c("ENO")); - /* Add the value from ENO param */ - ADD_PARAM_LIST(eno_param_name, NULL, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out) - - int nb_param = 1; - if (symbol->il_operand_list != NULL) - nb_param += ((list_c *)symbol->il_operand_list)->n; - - #include "il_code_gen.c" - - } - else { - function_name = symbol->function_name; - - /* determine the base data type returned by the function being called... */ - search_base_type_c search_base_type; - function_type_prefix = (symbol_c *)f_decl->type_name->accept(search_base_type); - - /* loop through each function parameter, find the value we should pass - * to it, and then output the c equivalent... - */ - - function_param_iterator_c fp_iterator(f_decl); - identifier_c *param_name; - for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { - symbol_c *param_type = fp_iterator.param_type(); - if (param_type == NULL) ERROR; - - function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); - - symbol_c *param_value = NULL; - - /* if it is the first parameter, semantics specifies that we should - * get the value off the IL default variable! - */ - if (1 == i) - param_value = &this->default_variable_name; - - /* Get the value from a foo( = ) style call */ - /* NOTE: the following line of code is not required in this case, but it doesn't - * harm to leave it in, as in the case of a non-formal syntax function call, - * it will always return NULL. - * We leave it in in case we later decide to merge this part of the code together - * with the function calling code in generate_c_st_c, which does require - * the following line... - */ - if (param_value == NULL) - param_value = function_call_param_iterator.search_f(param_name); - - /* Get the value from a foo() style call */ - if (param_value == NULL) { - param_value = function_call_param_iterator.next_nf(); - if (param_value != NULL && fp_iterator.is_en_eno_param_implicit()) ERROR; - } - - if (param_value == NULL && param_direction == function_param_iterator_c::direction_in) { - /* No value given for parameter, so we must use the default... */ - /* First check whether default value specified in function declaration...*/ - param_value = fp_iterator.default_value(); - } - - ADD_PARAM_LIST(param_name, param_value, param_type, fp_iterator.param_direction()) - } /* for(...) */ - } - - if (function_call_param_iterator.next_nf() != NULL) ERROR; + function_declaration_c *f_decl = (function_declaration_c *)symbol->called_function_declaration; + if (f_decl == NULL) ERROR; + + /* determine the base data type returned by the function being called... */ + search_base_type_c search_base_type; + function_type_prefix = (symbol_c *)f_decl->type_name->accept(search_base_type); + + function_name = symbol->function_name; + + /* loop through each function parameter, find the value we should pass + * to it, and then output the c equivalent... + */ + + function_param_iterator_c fp_iterator(f_decl); + identifier_c *param_name; + /* flag to remember whether we have already used the value stored in the default variable to pass to the first parameter */ + bool used_defvar = false; + /* flag to cirreclty handle calls to extensible standard functions (i.e. functions with variable number of input parameters) */ + bool found_first_extensible_parameter = false; + for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { + if (fp_iterator.is_extensible_param() && (!found_first_extensible_parameter)) { + /* We are calling an extensible function. Before passing the extensible + * parameters, we must add a dummy paramater value to tell the called + * function how many extensible parameters we will be passing. + * + * Note that stage 3 has already determined the number of extensible + * paramters, and stored that info in the abstract syntax tree. We simply + * re-use that value. + */ + /* NOTE: we are not freeing the malloc'd memory. This is not really a bug. + * Since we are writing a compiler, which runs to termination quickly, + * we can consider this as just memory required for the compilation process + * that will be free'd when the program terminates. + */ + char *tmp = (char *)malloc(32); /* enough space for a call with 10^31 (larger than 2^64) input parameters! */ + if (tmp == NULL) ERROR; + int res = snprintf(tmp, 32, "%d", symbol->extensible_param_count); + if ((res >= 32) || (res < 0)) ERROR; + identifier_c *param_value = new identifier_c(tmp); + uint_type_name_c *param_type = new uint_type_name_c(); + identifier_c *param_name = new identifier_c(""); + ADD_PARAM_LIST(param_name, param_value, param_type, function_param_iterator_c::direction_in) + found_first_extensible_parameter = true; + } + + symbol_c *param_type = fp_iterator.param_type(); + if (param_type == NULL) ERROR; + + function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); + + symbol_c *param_value = NULL; + + /* Get the value from a foo( = ) style call */ + /* NOTE: the following line of code is not required in this case, but it doesn't + * harm to leave it in, as in the case of a non-formal syntax function call, + * it will always return NULL. + * We leave it in in case we later decide to merge this part of the code together + * with the function calling code in generate_c_st_c, which does require + * the following line... + */ + if (param_value == NULL) + param_value = function_call_param_iterator.search_f(param_name); + + /* if it is the first parameter in a non-formal function call (which is the + * case being handled!), semantics specifies that we should + * get the value off the IL default variable! + * + * However, if the parameter is an implicitly defined EN or ENO parameter, we should not + * use the default variable as a source of data to pass to those parameters! + */ + if ((param_value == NULL) && (!used_defvar) && !fp_iterator.is_en_eno_param_implicit()) { + param_value = &this->default_variable_name; + used_defvar = true; + } + + /* Get the value from a foo() style call */ + if ((param_value == NULL) && !fp_iterator.is_en_eno_param_implicit()) { + param_value = function_call_param_iterator.next_nf(); + } + + /* if no more parameter values in function call, and the current parameter + * of the function declaration is an extensible parameter, we + * have reached the end, and should simply jump out of the for loop. + */ + if ((param_value == NULL) && (fp_iterator.is_extensible_param())) { + break; + } + + if ((param_value == NULL) && (param_direction == function_param_iterator_c::direction_in)) { + /* No value given for parameter, so we must use the default... */ + /* First check whether default value specified in function declaration...*/ + param_value = fp_iterator.default_value(); + } + + ADD_PARAM_LIST(param_name, param_value, param_type, fp_iterator.param_direction()) + } /* for(...) */ + + if (function_call_param_iterator.next_nf() != NULL) ERROR; if (NULL == function_type_prefix) ERROR; bool has_output_params = false; @@ -442,8 +472,16 @@ } } + /* Check whether we are calling an overloaded function! */ + /* (fdecl_mutiplicity==2) => calling overloaded function */ + int fdecl_mutiplicity = function_symtable.multiplicity(symbol->function_name); + if (fdecl_mutiplicity == 0) ERROR; + if (fdecl_mutiplicity == 1) + /* function being called is NOT overloaded! */ + f_decl = NULL; + if (has_output_params) - generate_inline(function_name, function_type_prefix, function_type_suffix, param_list); + generate_inline(function_name, function_type_prefix, function_type_suffix, param_list, f_decl); CLEAR_PARAM_LIST() @@ -460,87 +498,103 @@ function_call_param_iterator_c function_call_param_iterator(symbol); - function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); - if (f_decl == function_symtable.end_value()) { - function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name); - if (current_function_type == function_none) ERROR; - - function_type_prefix = (symbol_c *)search_expression_type->compute_standard_function_default(NULL, symbol); - - int nb_param = 0; - if (symbol->il_param_list != NULL) - nb_param += ((list_c *)symbol->il_param_list)->n; - - symbol_c *en_param_name = (symbol_c *)(new identifier_c("EN")); - /* Get the value from EN param */ - symbol_c *EN_param_value = function_call_param_iterator.search_f(en_param_name); - if (EN_param_value == NULL) - EN_param_value = (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c())); - else - nb_param --; - ADD_PARAM_LIST(en_param_name, EN_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_in) - - symbol_c *eno_param_name = (symbol_c *)(new identifier_c("ENO")); - /* Get the value from ENO param */ - symbol_c *ENO_param_value = function_call_param_iterator.search_f(eno_param_name); - if (ENO_param_value != NULL) - nb_param --; - ADD_PARAM_LIST(eno_param_name, ENO_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out) - - #include "st_code_gen.c" - - } - else { - function_name = symbol->function_name; - - /* determine the base data type returned by the function being called... */ - search_base_type_c search_base_type; - function_type_prefix = (symbol_c *)f_decl->type_name->accept(search_base_type); - - /* loop through each function parameter, find the value we should pass - * to it, and then output the c equivalent... - */ - - function_param_iterator_c fp_iterator(f_decl); - identifier_c *param_name; - for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { - symbol_c *param_type = fp_iterator.param_type(); - if (param_type == NULL) ERROR; - - function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); - - - symbol_c *param_value = NULL; - - /* Get the value from a foo( = ) style call */ - if (param_value == NULL) - param_value = function_call_param_iterator.search_f(param_name); - - /* Get the value from a foo() style call */ - /* NOTE: the following line of code is not required in this case, but it doesn't - * harm to leave it in, as in the case of a formal syntax function call, - * it will always return NULL. - * We leave it in in case we later decide to merge this part of the code together - * with the function calling code in generate_c_st_c, which does require - * the following line... - */ - if (param_value == NULL) { - param_value = function_call_param_iterator.next_nf(); - if (param_value != NULL && fp_iterator.is_en_eno_param_implicit()) ERROR; - } - - if (param_value == NULL) { - /* No value given for parameter, so we must use the default... */ - /* First check whether default value specified in function declaration...*/ - param_value = fp_iterator.default_value(); - } - - ADD_PARAM_LIST(param_name, param_value, param_type, fp_iterator.param_direction()) - } + function_declaration_c *f_decl = (function_declaration_c *)symbol->called_function_declaration; + if (f_decl == NULL) ERROR; + + /* determine the base data type returned by the function being called... */ + search_base_type_c search_base_type; + function_type_prefix = (symbol_c *)f_decl->type_name->accept(search_base_type); + if (NULL == function_type_prefix) ERROR; + + function_name = symbol->function_name; + + /* loop through each function parameter, find the value we should pass + * to it, and then output the c equivalent... + */ + function_param_iterator_c fp_iterator(f_decl); + identifier_c *param_name; + + /* flag to cirreclty handle calls to extensible standard functions (i.e. functions with variable number of input parameters) */ + bool found_first_extensible_parameter = false; + for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { + if (fp_iterator.is_extensible_param() && (!found_first_extensible_parameter)) { + /* We are calling an extensible function. Before passing the extensible + * parameters, we must add a dummy paramater value to tell the called + * function how many extensible parameters we will be passing. + * + * Note that stage 3 has already determined the number of extensible + * paramters, and stored that info in the abstract syntax tree. We simply + * re-use that value. + */ + /* NOTE: we are not freeing the malloc'd memory. This is not really a bug. + * Since we are writing a compiler, which runs to termination quickly, + * we can consider this as just memory required for the compilation process + * that will be free'd when the program terminates. + */ + char *tmp = (char *)malloc(32); /* enough space for a call with 10^31 (larger than 2^64) input parameters! */ + if (tmp == NULL) ERROR; + int res = snprintf(tmp, 32, "%d", symbol->extensible_param_count); + if ((res >= 32) || (res < 0)) ERROR; + identifier_c *param_value = new identifier_c(tmp); + uint_type_name_c *param_type = new uint_type_name_c(); + identifier_c *param_name = new identifier_c(""); + ADD_PARAM_LIST(param_name, param_value, param_type, function_param_iterator_c::direction_in) + found_first_extensible_parameter = true; + } + + if (fp_iterator.is_extensible_param()) { + /* since we are handling an extensible parameter, we must add the index to the + * parameter name so we can go looking for the value passed to the correct + * extended parameter (e.g. IN1, IN2, IN3, IN4, ...) + */ + char *tmp = (char *)malloc(32); /* enough space for a call with 10^31 (larger than 2^64) input parameters! */ + int res = snprintf(tmp, 32, "%d", fp_iterator.extensible_param_index()); + if ((res >= 32) || (res < 0)) ERROR; + param_name = new identifier_c(strdup2(param_name->value, tmp)); + if (param_name->value == NULL) ERROR; + } + + symbol_c *param_type = fp_iterator.param_type(); + if (param_type == NULL) ERROR; + + function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); + + symbol_c *param_value = NULL; + + /* Get the value from a foo( = ) style call */ + if (param_value == NULL) + param_value = function_call_param_iterator.search_f(param_name); + + /* Get the value from a foo() style call */ + /* NOTE: the following line of code is not required in this case, but it doesn't + * harm to leave it in, as in the case of a formal syntax function call, + * it will always return NULL. + * We leave it in in case we later decide to merge this part of the code together + * with the function calling code in generate_c_st_c, which does require + * the following line... + */ + if ((param_value == NULL) && !fp_iterator.is_en_eno_param_implicit()) { + param_value = function_call_param_iterator.next_nf(); + } + + /* if no more parameter values in function call, and the current parameter + * of the function declaration is an extensible parameter, we + * have reached the end, and should simply jump out of the for loop. + */ + if ((param_value == NULL) && (fp_iterator.is_extensible_param())) { + break; + } + + if ((param_value == NULL) && (param_direction == function_param_iterator_c::direction_in)) { + /* No value given for parameter, so we must use the default... */ + /* First check whether default value specified in function declaration...*/ + param_value = fp_iterator.default_value(); + } + + ADD_PARAM_LIST(param_name, param_value, param_type, fp_iterator.param_direction()) } if (function_call_param_iterator.next_nf() != NULL) ERROR; - if (NULL == function_type_prefix) ERROR; bool has_output_params = false; @@ -552,8 +606,16 @@ } } + /* Check whether we are calling an overloaded function! */ + /* (fdecl_mutiplicity==2) => calling overloaded function */ + int fdecl_mutiplicity = function_symtable.multiplicity(symbol->function_name); + if (fdecl_mutiplicity == 0) ERROR; + if (fdecl_mutiplicity == 1) + /* function being called is NOT overloaded! */ + f_decl = NULL; + if (has_output_params) - generate_inline(function_name, function_type_prefix, function_type_suffix, param_list); + generate_inline(function_name, function_type_prefix, function_type_suffix, param_list, f_decl); CLEAR_PARAM_LIST() @@ -580,81 +642,100 @@ function_call_param_iterator_c function_call_param_iterator(symbol); - function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); - if (f_decl == function_symtable.end_value()) { - /* The function called is not in the symtable, so we test if it is a - * standard function defined in standard */ - - function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name); - if (current_function_type == function_none) ERROR; - - function_type_prefix = search_expression_type->get_type(symbol); - - int nb_param = ((list_c *)parameter_assignment_list)->n; - - symbol_c *en_param_name = (symbol_c *)(new identifier_c("EN")); - /* Get the value from EN param */ - symbol_c *EN_param_value = function_call_param_iterator.search_f(en_param_name); - if (EN_param_value == NULL) - EN_param_value = (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c())); - else - nb_param --; - ADD_PARAM_LIST(en_param_name, EN_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_in) - - symbol_c *eno_param_name = (symbol_c *)(new identifier_c("ENO")); - /* Get the value from ENO param */ - symbol_c *ENO_param_value = function_call_param_iterator.search_f(eno_param_name); - if (ENO_param_value != NULL) - nb_param --; - ADD_PARAM_LIST(eno_param_name, ENO_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out) - - #include "st_code_gen.c" - - } - else { - function_name = symbol->function_name; - - /* determine the base data type returned by the function being called... */ - search_base_type_c search_base_type; - function_type_prefix = (symbol_c *)f_decl->type_name->accept(search_base_type); - - /* loop through each function parameter, find the value we should pass - * to it, and then output the c equivalent... + function_declaration_c *f_decl = (function_declaration_c *)symbol->called_function_declaration; + if (f_decl == NULL) ERROR; + + function_name = symbol->function_name; + + /* determine the base data type returned by the function being called... */ + search_base_type_c search_base_type; + function_type_prefix = (symbol_c *)f_decl->type_name->accept(search_base_type); + if (NULL == function_type_prefix) ERROR; + + /* loop through each function parameter, find the value we should pass + * to it, and then output the c equivalent... + */ + function_param_iterator_c fp_iterator(f_decl); + identifier_c *param_name; + /* flag to cirreclty handle calls to extensible standard functions (i.e. functions with variable number of input parameters) */ + bool found_first_extensible_parameter = false; + for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { + if (fp_iterator.is_extensible_param() && (!found_first_extensible_parameter)) { + /* We are calling an extensible function. Before passing the extensible + * parameters, we must add a dummy paramater value to tell the called + * function how many extensible parameters we will be passing. + * + * Note that stage 3 has already determined the number of extensible + * paramters, and stored that info in the abstract syntax tree. We simply + * re-use that value. + */ + /* NOTE: we are not freeing the malloc'd memory. This is not really a bug. + * Since we are writing a compiler, which runs to termination quickly, + * we can consider this as just memory required for the compilation process + * that will be free'd when the program terminates. + */ + char *tmp = (char *)malloc(32); /* enough space for a call with 10^31 (larger than 2^64) input parameters! */ + if (tmp == NULL) ERROR; + int res = snprintf(tmp, 32, "%d", symbol->extensible_param_count); + if ((res >= 32) || (res < 0)) ERROR; + identifier_c *param_value = new identifier_c(tmp); + uint_type_name_c *param_type = new uint_type_name_c(); + identifier_c *param_name = new identifier_c(""); + ADD_PARAM_LIST(param_name, param_value, param_type, function_param_iterator_c::direction_in) + found_first_extensible_parameter = true; + } + + if (fp_iterator.is_extensible_param()) { + /* since we are handling an extensible parameter, we must add the index to the + * parameter name so we can go looking for the value passed to the correct + * extended parameter (e.g. IN1, IN2, IN3, IN4, ...) + */ + char *tmp = (char *)malloc(32); /* enough space for a call with 10^31 (larger than 2^64) input parameters! */ + int res = snprintf(tmp, 32, "%d", fp_iterator.extensible_param_index()); + if ((res >= 32) || (res < 0)) ERROR; + param_name = new identifier_c(strdup2(param_name->value, tmp)); + if (param_name->value == NULL) ERROR; + } + + symbol_c *param_type = fp_iterator.param_type(); + if (param_type == NULL) ERROR; + + function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); + + symbol_c *param_value = NULL; + + /* Get the value from a foo( = ) style call */ + if (param_value == NULL) + param_value = function_call_param_iterator.search_f(param_name); + + /* Get the value from a foo() style call */ + if ((param_value == NULL) && !fp_iterator.is_en_eno_param_implicit()) { + param_value = function_call_param_iterator.next_nf(); + } + + /* if no more parameter values in function call, and the current parameter + * of the function declaration is an extensible parameter, we + * have reached the end, and should simply jump out of the for loop. */ - function_param_iterator_c fp_iterator(f_decl); - identifier_c *param_name; - for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { - symbol_c *param_type = fp_iterator.param_type(); - if (param_type == NULL) ERROR; - - function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); - - /* Get the value from a foo( = ) style call */ - symbol_c *param_value = function_call_param_iterator.search_f(param_name); - - /* Get the value from a foo() style call */ - if (param_value == NULL) { - param_value = function_call_param_iterator.next_nf(); - if (param_value != NULL && fp_iterator.is_en_eno_param_implicit()) ERROR; - } - - if (param_value == NULL && param_direction == function_param_iterator_c::direction_in) { - /* No value given for parameter, so we must use the default... */ - /* First check whether default value specified in function declaration...*/ - param_value = fp_iterator.default_value(); - } - - ADD_PARAM_LIST(param_name, param_value, param_type, param_direction) - } /* for(...) */ - // symbol->parameter_assignment->accept(*this); - } + if ((param_value == NULL) && (fp_iterator.is_extensible_param())) { + break; + } + + if ((param_value == NULL) && (param_direction == function_param_iterator_c::direction_in)) { + /* No value given for parameter, so we must use the default... */ + /* First check whether default value specified in function declaration...*/ + param_value = fp_iterator.default_value(); + } + + ADD_PARAM_LIST(param_name, param_value, param_type, param_direction) + } /* for(...) */ + // symbol->parameter_assignment->accept(*this); if (function_call_param_iterator.next_nf() != NULL) ERROR; - if (NULL == function_type_prefix) ERROR; - - bool has_output_params = false; - - PARAM_LIST_ITERATOR() { + + bool has_output_params = false; + + PARAM_LIST_ITERATOR() { if ((PARAM_DIRECTION == function_param_iterator_c::direction_out || PARAM_DIRECTION == function_param_iterator_c::direction_inout) && PARAM_VALUE != NULL) { @@ -662,12 +743,20 @@ } } + /* Check whether we are calling an overloaded function! */ + /* (fdecl_mutiplicity==2) => calling overloaded function */ + int fdecl_mutiplicity = function_symtable.multiplicity(symbol->function_name); + if (fdecl_mutiplicity == 0) ERROR; + if (fdecl_mutiplicity == 1) + /* function being called is NOT overloaded! */ + f_decl = NULL; + if (has_output_params) - generate_inline(function_name, function_type_prefix, function_type_suffix, param_list); + generate_inline(function_name, function_type_prefix, function_type_suffix, param_list, f_decl); CLEAR_PARAM_LIST() - return NULL; + return NULL; } }; /* generate_c_inlinefcall_c */ diff -r ba80c3ceb6fb -r 2c3c4dc34979 stage4/generate_c/generate_c_sfc.cc --- a/stage4/generate_c/generate_c_sfc.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/stage4/generate_c/generate_c_sfc.cc Fri Jul 29 16:03:28 2011 +0100 @@ -519,7 +519,7 @@ s4o.print("activated"); } if (strcmp(qualifier, "D") == 0 || strcmp(qualifier, "L") == 0) { - s4o.print("active && __TIME_CMP("); + s4o.print("active && __time_cmp("); print_step_argument(current_step, "elapsed_time"); s4o.print(", "); symbol->action_time->accept(*this); @@ -640,7 +640,9 @@ /* generate elapsed_time initializations */ s4o.print(s4o.indent_spaces + "// Calculate elapsed_time\n"); s4o.print(s4o.indent_spaces +"current_time = __CURRENT_TIME;\n"); - s4o.print(s4o.indent_spaces +"elapsed_time = __time_sub(__BOOL_LITERAL(TRUE), NULL, current_time, "); +// s4o.print(s4o.indent_spaces +"elapsed_time = __time_sub(__BOOL_LITERAL(TRUE), NULL, current_time, "); +// s4o.print(s4o.indent_spaces +"elapsed_time = SUB_TIME(__BOOL_LITERAL(TRUE), NULL, current_time, "); + s4o.print(s4o.indent_spaces +"elapsed_time = __time_sub(current_time, "); print_variable_prefix(); s4o.print("__lasttick_time);\n"); s4o.print(s4o.indent_spaces); @@ -686,7 +688,9 @@ s4o.indent_right(); s4o.print(s4o.indent_spaces); print_variable_prefix(); - s4o.print("__step_list[i].elapsed_time = __time_add(__BOOL_LITERAL(TRUE), NULL, "); +// s4o.print("__step_list[i].elapsed_time = __time_add(__BOOL_LITERAL(TRUE), NULL, "); +// s4o.print("__step_list[i].elapsed_time = ADD_TIME(__BOOL_LITERAL(TRUE), NULL, "); + s4o.print("__step_list[i].elapsed_time = __time_add("); print_variable_prefix(); s4o.print("__step_list[i].elapsed_time, elapsed_time);\n"); s4o.indent_left(); @@ -710,17 +714,19 @@ print_variable_prefix(); s4o.print("__action_list[i].reset = 0;\n"); s4o.print(s4o.indent_spaces + "if ("); - s4o.print("__TIME_CMP("); + s4o.print("__time_cmp("); print_variable_prefix(); s4o.print("__action_list[i].set_remaining_time, __time_to_timespec(1, 0, 0, 0, 0, 0)) > 0) {\n"); s4o.indent_right(); s4o.print(s4o.indent_spaces); print_variable_prefix(); - s4o.print("__action_list[i].set_remaining_time = __time_sub(__BOOL_LITERAL(TRUE), NULL, "); +// s4o.print("__action_list[i].set_remaining_time = __time_sub(__BOOL_LITERAL(TRUE), NULL, "); +// s4o.print("__action_list[i].set_remaining_time = SUB_TIME(__BOOL_LITERAL(TRUE), NULL, "); + s4o.print("__action_list[i].set_remaining_time = __time_sub("); print_variable_prefix(); s4o.print("__action_list[i].set_remaining_time, elapsed_time);\n"); s4o.print(s4o.indent_spaces + "if ("); - s4o.print("__TIME_CMP("); + s4o.print("__time_cmp("); print_variable_prefix(); s4o.print("__action_list[i].set_remaining_time, __time_to_timespec(1, 0, 0, 0, 0, 0)) <= 0) {\n"); s4o.indent_right(); @@ -735,17 +741,19 @@ s4o.indent_left(); s4o.print(s4o.indent_spaces + "}\n"); s4o.print(s4o.indent_spaces + "if ("); - s4o.print("__TIME_CMP("); + s4o.print("__time_cmp("); print_variable_prefix(); s4o.print("__action_list[i].reset_remaining_time, __time_to_timespec(1, 0, 0, 0, 0, 0)) > 0) {\n"); s4o.indent_right(); s4o.print(s4o.indent_spaces); print_variable_prefix(); - s4o.print("__action_list[i].reset_remaining_time = __time_sub(__BOOL_LITERAL(TRUE), NULL, "); +// s4o.print("__action_list[i].reset_remaining_time = __time_sub(__BOOL_LITERAL(TRUE), NULL, "); +// s4o.print("__action_list[i].reset_remaining_time = SUB_TIME(__BOOL_LITERAL(TRUE), NULL, "); + s4o.print("__action_list[i].reset_remaining_time = __time_sub("); print_variable_prefix(); s4o.print("__action_list[i].reset_remaining_time, elapsed_time);\n"); s4o.print(s4o.indent_spaces + "if ("); - s4o.print("__TIME_CMP("); + s4o.print("__time_cmp("); print_variable_prefix(); s4o.print("__action_list[i].reset_remaining_time, __time_to_timespec(1, 0, 0, 0, 0, 0)) <= 0) {\n"); s4o.indent_right(); diff -r ba80c3ceb6fb -r 2c3c4dc34979 stage4/generate_c/generate_c_st.cc --- a/stage4/generate_c/generate_c_st.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/stage4/generate_c/generate_c_st.cc Fri Jul 29 16:03:28 2011 +0100 @@ -35,6 +35,9 @@ */ + +#include "../../util/strdup.hh" + /***********************************************************************/ /***********************************************************************/ /***********************************************************************/ @@ -434,7 +437,7 @@ ERROR; if (search_expression_type->is_time_type(left_type) || search_expression_type->is_string_type(left_type)) - return print_compare_function("__eq_", left_type, symbol->l_exp, symbol->r_exp); + return print_compare_function("EQ_", left_type, symbol->l_exp, symbol->r_exp); return print_binary_expression(symbol->l_exp, symbol->r_exp, " == "); } @@ -445,7 +448,7 @@ ERROR; if (search_expression_type->is_time_type(left_type) || search_expression_type->is_string_type(left_type)) - return print_compare_function("__ne_", left_type, symbol->l_exp, symbol->r_exp); + return print_compare_function("NE_", left_type, symbol->l_exp, symbol->r_exp); return print_binary_expression(symbol->l_exp, symbol->r_exp, " != "); } @@ -456,7 +459,7 @@ ERROR; if (search_expression_type->is_time_type(left_type) || search_expression_type->is_string_type(left_type)) - return print_compare_function("__lt_", left_type, symbol->l_exp, symbol->r_exp); + return print_compare_function("LT_", left_type, symbol->l_exp, symbol->r_exp); if (!search_base_type.type_is_enumerated(left_type)) return print_binary_expression(symbol->l_exp, symbol->r_exp, " < "); ERROR; @@ -470,7 +473,7 @@ ERROR; if (search_expression_type->is_time_type(left_type) || search_expression_type->is_string_type(left_type)) - return print_compare_function("__gt_", left_type, symbol->l_exp, symbol->r_exp); + return print_compare_function("GT_", left_type, symbol->l_exp, symbol->r_exp); if (!search_base_type.type_is_enumerated(left_type)) return print_binary_expression(symbol->l_exp, symbol->r_exp, " > "); ERROR; @@ -484,7 +487,7 @@ ERROR; if (search_expression_type->is_time_type(left_type) || search_expression_type->is_string_type(left_type)) - return print_compare_function("__le_", left_type, symbol->l_exp, symbol->r_exp); + return print_compare_function("LE_", left_type, symbol->l_exp, symbol->r_exp); if (!search_base_type.type_is_enumerated(left_type)) return print_binary_expression(symbol->l_exp, symbol->r_exp, " <= "); ERROR; @@ -498,7 +501,7 @@ ERROR; if (search_expression_type->is_time_type(left_type) || search_expression_type->is_string_type(left_type)) - return print_compare_function("__ge_", left_type, symbol->l_exp, symbol->r_exp); + return print_compare_function("GE_", left_type, symbol->l_exp, symbol->r_exp); if (!search_base_type.type_is_enumerated(left_type)) return print_binary_expression(symbol->l_exp, symbol->r_exp, " >= "); ERROR; @@ -511,7 +514,7 @@ if ((typeid(*left_type) == typeid(time_type_name_c) && typeid(*right_type) == typeid(time_type_name_c)) || (typeid(*left_type) == typeid(tod_type_name_c) && typeid(*right_type) == typeid(time_type_name_c)) || (typeid(*left_type) == typeid(dt_type_name_c) && typeid(*right_type) == typeid(time_type_name_c))) - return print_binary_function("__TIME_ADD", symbol->l_exp, symbol->r_exp); + return print_binary_function("__time_add", symbol->l_exp, symbol->r_exp); if (!search_expression_type->is_same_type(left_type, right_type)) ERROR; if (search_expression_type->is_integer_type(left_type) || search_expression_type->is_real_type(left_type)) @@ -529,7 +532,7 @@ (typeid(*left_type) == typeid(tod_type_name_c) && typeid(*right_type) == typeid(tod_type_name_c)) || (typeid(*left_type) == typeid(dt_type_name_c) && typeid(*right_type) == typeid(time_type_name_c)) || (typeid(*left_type) == typeid(dt_type_name_c) && typeid(*right_type) == typeid(dt_type_name_c))) - return print_binary_function("__TIME_SUB", symbol->l_exp, symbol->r_exp); + return print_binary_function("__time_sub", symbol->l_exp, symbol->r_exp); if (!search_expression_type->is_same_type(left_type, right_type)) ERROR; if (search_expression_type->is_integer_type(left_type) || search_expression_type->is_real_type(left_type)) @@ -543,7 +546,7 @@ symbol_c *right_type = search_expression_type->get_type(symbol->r_exp); if ((typeid(*left_type) == typeid(time_type_name_c) && search_expression_type->is_integer_type(right_type)) || (typeid(*left_type) == typeid(time_type_name_c) && search_expression_type->is_real_type(right_type))) - return print_binary_function("__TIME_MUL", symbol->l_exp, symbol->r_exp); + return print_binary_function("__time_mul", symbol->l_exp, symbol->r_exp); if (!search_expression_type->is_same_type(left_type, right_type)) ERROR; if (search_expression_type->is_integer_type(left_type) || search_expression_type->is_real_type(left_type)) @@ -557,7 +560,7 @@ symbol_c *right_type = search_expression_type->get_type(symbol->r_exp); if ((typeid(*left_type) == typeid(time_type_name_c) && search_expression_type->is_integer_type(right_type)) || (typeid(*left_type) == typeid(time_type_name_c) && search_expression_type->is_real_type(right_type))) - return print_binary_function("__TIME_DIV", symbol->l_exp, symbol->r_exp); + return print_binary_function("__time_div", symbol->l_exp, symbol->r_exp); if (!search_expression_type->is_same_type(left_type, right_type)) ERROR; if (search_expression_type->is_integer_type(left_type) || search_expression_type->is_real_type(left_type)) @@ -614,71 +617,89 @@ function_call_param_iterator_c function_call_param_iterator(symbol); - function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); - if (f_decl == function_symtable.end_value()) { - /* The function called is not in the symtable, so we test if it is a - * standard function defined in standard */ - - function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name); - if (current_function_type == function_none) ERROR; - - symbol_c *function_return_type = search_expression_type->get_type(symbol); - - int nb_param = ((list_c *)parameter_assignment_list)->n; - - symbol_c *en_param_name = (symbol_c *)(new identifier_c("EN")); - /* Get the value from EN param */ - symbol_c *EN_param_value = function_call_param_iterator.search_f(en_param_name); - if (EN_param_value == NULL) - EN_param_value = (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c())); - else - nb_param --; - ADD_PARAM_LIST(en_param_name, EN_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_in) - - symbol_c *eno_param_name = (symbol_c *)(new identifier_c("ENO")); - /* Get the value from ENO param */ - symbol_c *ENO_param_value = function_call_param_iterator.search_f(eno_param_name); - if (ENO_param_value != NULL) - nb_param --; - ADD_PARAM_LIST(eno_param_name, ENO_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out) - - #include "st_code_gen.c" - - } - else { - function_name = symbol->function_name; - - /* loop through each function parameter, find the value we should pass - * to it, and then output the c equivalent... + function_declaration_c *f_decl = (function_declaration_c *)symbol->called_function_declaration; + if (f_decl == NULL) ERROR; + + function_name = symbol->function_name; + + /* loop through each function parameter, find the value we should pass + * to it, and then output the c equivalent... + */ + function_param_iterator_c fp_iterator(f_decl); + identifier_c *param_name; + /* flag to cirreclty handle calls to extensible standard functions (i.e. functions with variable number of input parameters) */ + bool found_first_extensible_parameter = false; + for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { + if (fp_iterator.is_extensible_param() && (!found_first_extensible_parameter)) { + /* We are calling an extensible function. Before passing the extensible + * parameters, we must add a dummy paramater value to tell the called + * function how many extensible parameters we will be passing. + * + * Note that stage 3 has already determined the number of extensible + * paramters, and stored that info in the abstract syntax tree. We simply + * re-use that value. + */ + /* NOTE: we are not freeing the malloc'd memory. This is not really a bug. + * Since we are writing a compiler, which runs to termination quickly, + * we can consider this as just memory required for the compilation process + * that will be free'd when the program terminates. + */ + char *tmp = (char *)malloc(32); /* enough space for a call with 10^31 (larger than 2^64) input parameters! */ + if (tmp == NULL) ERROR; + int res = snprintf(tmp, 32, "%d", symbol->extensible_param_count); + if ((res >= 32) || (res < 0)) ERROR; + identifier_c *param_value = new identifier_c(tmp); + uint_type_name_c *param_type = new uint_type_name_c(); + identifier_c *param_name = new identifier_c(""); + ADD_PARAM_LIST(param_name, param_value, param_type, function_param_iterator_c::direction_in) + found_first_extensible_parameter = true; + } + + if (fp_iterator.is_extensible_param()) { + /* since we are handling an extensible parameter, we must add the index to the + * parameter name so we can go looking for the value passed to the correct + * extended parameter (e.g. IN1, IN2, IN3, IN4, ...) + */ + char *tmp = (char *)malloc(32); /* enough space for a call with 10^31 (larger than 2^64) input parameters! */ + int res = snprintf(tmp, 32, "%d", fp_iterator.extensible_param_index()); + if ((res >= 32) || (res < 0)) ERROR; + param_name = new identifier_c(strdup2(param_name->value, tmp)); + if (param_name->value == NULL) ERROR; + } + + symbol_c *param_type = fp_iterator.param_type(); + if (param_type == NULL) ERROR; + + function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); + + symbol_c *param_value = NULL; + + /* Get the value from a foo( = ) style call */ + if (param_value == NULL) + param_value = function_call_param_iterator.search_f(param_name); + + /* Get the value from a foo() style call */ + if ((param_value == NULL) && !fp_iterator.is_en_eno_param_implicit()) { + param_value = function_call_param_iterator.next_nf(); + } + + /* if no more parameter values in function call, and the current parameter + * of the function declaration is an extensible parameter, we + * have reached the end, and should simply jump out of the for loop. */ - function_param_iterator_c fp_iterator(f_decl); - identifier_c *param_name; - for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { - - symbol_c *param_type = fp_iterator.param_type(); - if (param_type == NULL) ERROR; - - function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); - - /* Get the value from a foo( = ) style call */ - symbol_c *param_value = function_call_param_iterator.search_f(param_name); - - /* Get the value from a foo() style call */ - if (param_value == NULL) { - param_value = function_call_param_iterator.next_nf(); - if (param_value != NULL && fp_iterator.is_en_eno_param_implicit()) ERROR; - } - - if (param_value == NULL && param_direction == function_param_iterator_c::direction_in) { - /* No value given for parameter, so we must use the default... */ - /* First check whether default value specified in function declaration...*/ - param_value = fp_iterator.default_value(); - } - - ADD_PARAM_LIST(param_name, param_value, param_type, param_direction) - } /* for(...) */ - // symbol->parameter_assignment->accept(*this); - } + if ((param_value == NULL) && (fp_iterator.is_extensible_param())) { + break; + } + + if ((param_value == NULL) && (param_direction == function_param_iterator_c::direction_in)) { + /* No value given for parameter, so we must use the default... */ + /* First check whether default value specified in function declaration...*/ + param_value = fp_iterator.default_value(); + } + + ADD_PARAM_LIST(param_name, param_value, param_type, param_direction) + } /* for(...) */ + // symbol->parameter_assignment->accept(*this); if (function_call_param_iterator.next_nf() != NULL) ERROR; @@ -686,15 +707,18 @@ if (!this->is_variable_prefix_null()) { PARAM_LIST_ITERATOR() { - if ((PARAM_DIRECTION == function_param_iterator_c::direction_out || - PARAM_DIRECTION == function_param_iterator_c::direction_inout) && - PARAM_VALUE != NULL) { - if (!has_output_params) { - has_output_params = true; - } - } - } - } + if ((PARAM_DIRECTION == function_param_iterator_c::direction_out || + PARAM_DIRECTION == function_param_iterator_c::direction_inout) && + PARAM_VALUE != NULL) { + has_output_params = true; + } + } + } + + /* Check whether we are calling an overloaded function! */ + /* (fdecl_mutiplicity==2) => calling overloaded function */ + int fdecl_mutiplicity = function_symtable.multiplicity(symbol->function_name); + if (fdecl_mutiplicity == 0) ERROR; if (function_type_prefix != NULL) { s4o.print("("); @@ -702,20 +726,32 @@ s4o.print(")"); } if (function_type_suffix != NULL) { - function_type_suffix = search_expression_type->default_literal_type(function_type_prefix); + function_type_suffix = search_expression_type->default_literal_type(function_type_prefix); } if (has_output_params) { - fcall_number++; - s4o.print("__"); + fcall_number++; + s4o.print("__"); fbname->accept(*this); s4o.print("_"); function_name->accept(*this); + if (fdecl_mutiplicity == 2) { + /* function being called is overloaded! */ + s4o.print("__"); + print_function_parameter_data_types_c overloaded_func_suf(&s4o); + f_decl->accept(overloaded_func_suf); + } if (function_type_suffix != NULL) function_type_suffix->accept(*this); s4o.print_integer(fcall_number); } else { function_name->accept(*this); + if (fdecl_mutiplicity == 2) { + /* function being called is overloaded! */ + s4o.print("__"); + print_function_parameter_data_types_c overloaded_func_suf(&s4o); + f_decl->accept(overloaded_func_suf); + } if (function_type_suffix != NULL) function_type_suffix->accept(*this); } @@ -845,7 +881,10 @@ symbol_c *param_value = function_call_param_iterator.search_f(param_name); /* Get the value from a foo() style call */ - if (param_value == NULL) + /* When using the informal invocation style, user can not pass values to EN or ENO parameters if these + * were implicitly defined! + */ + if ((param_value == NULL) && !fp_iterator.is_en_eno_param_implicit()) param_value = function_call_param_iterator.next_nf(); symbol_c *param_type = fp_iterator.param_type(); @@ -889,7 +928,10 @@ symbol_c *param_value = function_call_param_iterator.search_f(param_name); /* Get the value from a foo() style call */ - if (param_value == NULL) + /* When using the informal invocation style, user can not pass values to EN or ENO parameters if these + * were implicitly defined! + */ + if ((param_value == NULL) && !fp_iterator.is_en_eno_param_implicit()) param_value = function_call_param_iterator.next_nf(); /* now output the value assignment */ diff -r ba80c3ceb6fb -r 2c3c4dc34979 stage4/generate_c/generate_c_typedecl.cc --- a/stage4/generate_c/generate_c_typedecl.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/stage4/generate_c/generate_c_typedecl.cc Fri Jul 29 16:03:28 2011 +0100 @@ -76,10 +76,6 @@ basetypedeclaration_t current_basetypedeclaration; - int extract_integer(symbol_c *integer) { - return atoi(((integer_c *)integer)->value); - } - void print_integer(unsigned int integer) { char str[10]; sprintf(str, "%d", integer); diff -r ba80c3ceb6fb -r 2c3c4dc34979 stage4/generate_iec/generate_iec.cc --- a/stage4/generate_iec/generate_iec.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/stage4/generate_iec/generate_iec.cc Fri Jul 29 16:03:28 2011 +0100 @@ -704,6 +704,32 @@ void *visit(var1_list_c *symbol) {return print_list(symbol, "", ", ");} +/* | [var1_list ','] variable_name '..' */ +/* NOTE: This is an extension to the standard!!! */ +/* In order to be able to handle extensible standard functions + * (i.e. standard functions that may have a variable number of + * input parameters, such as AND(word#33, word#44, word#55, word#66), + * we have extended the acceptable syntax to allow var_name '..' + * in an input variable declaration. + * + * This allows us to parse the declaration of standard + * extensible functions and load their interface definition + * into the abstract syntax tree just like we do to other + * user defined functions. + * This has the advantage that we can later do semantic + * checking of calls to functions (be it a standard or user defined + * function) in (almost) exactly the same way. + * + * Of course, we have a flag that disables this syntax when parsing user + * written code, so we only allow this extra syntax while parsing the + * 'header' file that declares all the standard IEC 61131-3 functions. + */ +void *visit(extensible_input_parameter_c *symbol) { + symbol->var_name->accept(*this); + s4o.print(" .. "); + return NULL; +} + /* var1_list ':' array_spec_init */ void *visit(array_var_init_decl_c *symbol) { @@ -930,14 +956,10 @@ return NULL; } -/* STRING ['[' integer ']'] [ASSIGN single_byte_character_string] */ -/* integer ->may be NULL ! */ +/* single_byte_limited_len_string_spec [ASSIGN single_byte_character_string] */ /* single_byte_character_string ->may be NULL ! */ void *visit(single_byte_string_spec_c *symbol) { - s4o.print("STRING ["); - if (symbol->integer != NULL) - symbol->integer->accept(*this); - s4o.print("]"); + symbol->string_spec->accept(*this); if (symbol->single_byte_character_string != NULL) { s4o.print(" := "); symbol->single_byte_character_string->accept(*this); @@ -945,6 +967,18 @@ return NULL; } +/* STRING ['[' integer ']'] */ +/* integer ->may be NULL ! */ +void *visit(single_byte_limited_len_string_spec_c *symbol) { + symbol->string_type_name->accept(*this); + if (symbol->character_string_len != NULL) { + s4o.print(" ["); + symbol->character_string_len->accept(*this); + s4o.print("]"); + } + return NULL; +} + /* var1_list ':' double_byte_string_spec */ void *visit(double_byte_string_var_declaration_c *symbol) { symbol->var1_list->accept(*this); @@ -953,14 +987,11 @@ return NULL; } -/* WSTRING ['[' integer ']'] [ASSIGN double_byte_character_string] */ +/* double_byte_limited_len_string_spec [ASSIGN double_byte_character_string] */ /* integer ->may be NULL ! */ /* double_byte_character_string ->may be NULL ! */ void *visit(double_byte_string_spec_c *symbol) { - s4o.print("WSTRING ["); - if (symbol->integer != NULL) - symbol->integer->accept(*this); - s4o.print("]"); + symbol->string_spec->accept(*this); if (symbol->double_byte_character_string != NULL) { s4o.print(" := "); symbol->double_byte_character_string->accept(*this); @@ -968,6 +999,18 @@ return NULL; } +/* WSTRING ['[' integer ']'] */ +/* integer ->may be NULL ! */ +void *visit(double_byte_limited_len_string_spec_c *symbol) { + symbol->string_type_name->accept(*this); + if (symbol->character_string_len != NULL) { + s4o.print(" ["); + symbol->character_string_len->accept(*this); + s4o.print("]"); + } + return NULL; +} + /*| VAR [RETAIN|NON_RETAIN] incompl_located_var_decl_list END_VAR */ /* option ->may be NULL ! */ void *visit(incompl_located_var_declarations_c *symbol) { diff -r ba80c3ceb6fb -r 2c3c4dc34979 util/dsymtable.cc --- a/util/dsymtable.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/util/dsymtable.cc Fri Jul 29 16:03:28 2011 +0100 @@ -91,6 +91,28 @@ #endif + +/* Determine how many entries are associated to key identifier_str */ +/* returns: + * 0: if no entry is found + * 1: if 1 entry is found + * 2: if more than 1 entry is found + */ +template +int dsymtable_c::multiplicity(const char *identifier_str) { + iterator lower = _base.lower_bound(identifier_str); + if (lower == _base.end()) return 0; + + iterator upper = _base.upper_bound(identifier_str); + iterator second = lower; + second++; + + if (second == upper) return 1; + + return 2; +} + + /* returns null_value if not found! */ template value_type dsymtable_c::find_value(const char *identifier_str) { @@ -104,11 +126,11 @@ template -value_type dsymtable_c::find_value(const symbol_c *symbol) { +const char * dsymtable_c::symbol_to_string(const symbol_c *symbol) { const token_c *name = dynamic_cast(symbol); if (name == NULL) ERROR; - return find_value(name->value); + return name->value; } diff -r ba80c3ceb6fb -r 2c3c4dc34979 util/dsymtable.hh --- a/util/dsymtable.hh Mon Jul 11 09:47:27 2011 +0100 +++ b/util/dsymtable.hh Fri Jul 29 16:03:28 2011 +0100 @@ -78,6 +78,7 @@ private: void reset(void); /* clear all entries... */ + const char *symbol_to_string(const symbol_c *symbol); public: dsymtable_c(void) {}; @@ -85,12 +86,35 @@ void insert(const char *identifier_str, value_t value); void insert(const symbol_c *symbol, value_t value); + /* Determine how many entries are associated to key identifier_str */ + /* returns: + * 0: if no entry is found + * 1: if 1 entry is found + * 2: if more than 1 entry is found + */ + int multiplicity(const char *identifier_str); + int multiplicity(const symbol_c *symbol) {return multiplicity(symbol_to_string(symbol));} + /* Search for an entry. Will return end_value() if not found */ value_t end_value(void) {return null_value;} value_t find_value(const char *identifier_str); - value_t find_value(const symbol_c *symbol); + value_t find_value(const symbol_c *symbol) {return find_value(symbol_to_string(symbol));} - iterator find(const char *identifier_str) {return _base.find(identifier_str);} + /* Search for an entry associated with identifier_str. Will return end() if not found */ + iterator find(const char *identifier_str) {return _base.find(identifier_str);} + iterator find(const symbol_c *symbol) {return find(symbol_to_string(symbol));} + + /* Search for the first entry associated with (i.e. with key ==) identifier_str. Will return end() if not found */ + /* Basically, the same as find() */ + iterator lower_bound(const char *identifier_str) {return _base.lower_bound(identifier_str);} + iterator lower_bound(const symbol_c *symbol) {return lower_bound(symbol_to_string(symbol));} + + /* Search for the first entry with key greater than identifier_str. Will return end() if not found */ + iterator upper_bound(const char *identifier_str) {return _base.upper_bound(identifier_str);} + iterator upper_bound(const symbol_c *symbol) {return upper_bound(symbol_to_string(symbol));} + + /* get the value to which an iterator is pointing to... */ + value_t get_value(const iterator i) {return i->second;} /* iterators pointing to beg/end of map... */ iterator begin() {return _base.begin();}