stage1_2/iec_flex.ll
changeset 1021 21a97cdb317d
parent 1020 36fb9443b6ea
child 1031 ce026aee03e0
equal deleted inserted replaced
1008:59435d4c5e0c 1021:21a97cdb317d
   148  * apropriately whenever it comes across an (*#include <filename> *) directive...
   148  * apropriately whenever it comes across an (*#include <filename> *) directive...
   149  */
   149  */
   150 const char *current_filename = NULL;
   150 const char *current_filename = NULL;
   151 
   151 
   152 
   152 
   153 
       
   154 /* We will not be using unput() in our flex code... */
       
   155 /* NOTE: it seems that this #define is no longer needed, It has been 
       
   156  * replaced by %option nounput.
       
   157  * Should we simply delete it?
       
   158  * For now leave it in, in case someone is using an old version of flex.
       
   159  * In any case, the most harm that can result in a warning message
       
   160  * when compiling iec.flex.c:
       
   161  * warning: ‘void yyunput(int, char*)’ defined but not used
       
   162  */
       
   163 #define YY_NO_UNPUT
       
   164 
   153 
   165 /* Variable defined by the bison parser.
   154 /* Variable defined by the bison parser.
   166  * It must be initialised with the location
   155  * It must be initialised with the location
   167  * of the token being parsed.
   156  * of the token being parsed.
   168  * This is only needed if we want to keep
   157  * This is only needed if we want to keep
   234  * but first return to the stream an additional character to mark the end of the token. 
   223  * but first return to the stream an additional character to mark the end of the token. 
   235  */
   224  */
   236 void unput_and_mark(const char c);
   225 void unput_and_mark(const char c);
   237 
   226 
   238 void include_file(const char *include_filename);
   227 void include_file(const char *include_filename);
       
   228 
       
   229 /* The body_state tries to find a ';' before a END_PROGRAM, END_FUNCTION or END_FUNCTION_BLOCK or END_ACTION
       
   230  * To do so, it must ignore comments and pragmas. This means that we cannot do this in a signle lex rule.
       
   231  * However, we must store any text we consume in every rule, so we can push it back into the buffer
       
   232  * once we have decided if we are parsing ST or IL code. The following functions manage that buffer used by
       
   233  * the body_state.
       
   234  */
       
   235 void  append_bodystate_buffer(const char *yytext);
       
   236 void   unput_bodystate_buffer(void);
       
   237 int  isempty_bodystate_buffer(void);
   239 
   238 
   240 int GetNextChar(char *b, int maxBuffer);
   239 int GetNextChar(char *b, int maxBuffer);
   241 %}
   240 %}
   242 
   241 
   243 
   242 
   967 
   966 
   968 	/* We start off by searching for the pragmas we handle in the lexical parser. */
   967 	/* We start off by searching for the pragmas we handle in the lexical parser. */
   969 <INITIAL>{file_include_pragma}	unput_text(0); yy_push_state(include_beg);
   968 <INITIAL>{file_include_pragma}	unput_text(0); yy_push_state(include_beg);
   970 
   969 
   971 	/* Pragmas sent to syntax analyser (bison) */
   970 	/* Pragmas sent to syntax analyser (bison) */
   972 {disable_code_generation_pragma}               return disable_code_generation_pragma_token;
   971 	/* NOTE: In the vardecl_list_state we only process the pragmas between two consecutive VAR .. END_VAR blocks.
   973 {enable_code_generation_pragma}                return enable_code_generation_pragma_token;
   972 	 *       We do not process any pragmas trailing after the last END_VAR. We leave that to the body_state.
   974 <body_state,vardecl_list_state>{disable_code_generation_pragma}   return disable_code_generation_pragma_token;
   973 	 *       This is because the pragmas are stored in a statement_list or instruction_list (in bison),
   975 <body_state,vardecl_list_state>{enable_code_generation_pragma}    return enable_code_generation_pragma_token;
   974 	 *       but these lists must start with the special tokens start_IL_body_token/start_ST_body_token.
   976 
   975 	 *       This means that these special tokens must be generated (by the body_state) before processing
       
   976 	 *       the pragme => we cannot process the trailing pragmas in the vardecl_list_state state.
       
   977 	 */
       
   978 {disable_code_generation_pragma}				return disable_code_generation_pragma_token;
       
   979 {enable_code_generation_pragma}					return enable_code_generation_pragma_token;
       
   980 <vardecl_list_state>{disable_code_generation_pragma}/(VAR)	return disable_code_generation_pragma_token; 
       
   981 <vardecl_list_state>{enable_code_generation_pragma}/(VAR)	return enable_code_generation_pragma_token;  
       
   982 <body_state>{disable_code_generation_pragma}			append_bodystate_buffer(yytext); /* in body state we do not process any tokens, we simply store them for later processing! */
       
   983 <body_state>{enable_code_generation_pragma}			append_bodystate_buffer(yytext); /* in body state we do not process any tokens, we simply store them for later processing! */
   977 	/* Any other pragma we find, we just pass it up to the syntax parser...   */
   984 	/* Any other pragma we find, we just pass it up to the syntax parser...   */
   978 	/* Note that the <body_state> state is exclusive, so we have to include it here too. */
   985 	/* Note that the <body_state> state is exclusive, so we have to include it here too. */
       
   986 <body_state>{pragma}					append_bodystate_buffer(yytext); /* in body state we do not process any tokens, we simply store them for later processing! */
   979 {pragma}	{/* return the pragmma without the enclosing '{' and '}' */
   987 {pragma}	{/* return the pragmma without the enclosing '{' and '}' */
   980 		 int cut = yytext[1]=='{'?2:1;
   988 		 int cut = yytext[1]=='{'?2:1;
   981 		 yytext[strlen(yytext)-cut] = '\0';
   989 		 yytext[strlen(yytext)-cut] = '\0';
   982 		 yylval.ID=strdup(yytext+cut);
   990 		 yylval.ID=strdup(yytext+cut);
   983 		 return pragma_token;
   991 		 return pragma_token;
   984 		}
   992 		}
   985 <body_state,vardecl_list_state>{pragma} {/* return the pragmma without the enclosing '{' and '}' */
   993 <vardecl_list_state>{pragma}/(VAR) {/* return the pragmma without the enclosing '{' and '}' */
   986 		 int cut = yytext[1]=='{'?2:1;
   994 		 int cut = yytext[1]=='{'?2:1;
   987 		 yytext[strlen(yytext)-cut] = '\0';
   995 		 yytext[strlen(yytext)-cut] = '\0';
   988 		 yylval.ID=strdup(yytext+cut);
   996 		 yylval.ID=strdup(yytext+cut);
   989 		 return pragma_token;
   997 		 return pragma_token;
   990 		}
   998 		}
  1068 	/* Handle all the state changes! */
  1076 	/* Handle all the state changes! */
  1069 	/*********************************/
  1077 	/*********************************/
  1070 
  1078 
  1071 	/* INITIAL -> header_state */
  1079 	/* INITIAL -> header_state */
  1072 <INITIAL>{
  1080 <INITIAL>{
  1073 	/* NOTE: how about functions that do not declare variables, and go directly to the body_state???
  1081 FUNCTION{st_whitespace} 		if (get_preparse_state()) BEGIN(get_pou_name_state); else {BEGIN(header_state);/* printf("\nChanging to header_state\n"); */} return FUNCTION;
       
  1082 FUNCTION_BLOCK{st_whitespace}		if (get_preparse_state()) BEGIN(get_pou_name_state); else {BEGIN(header_state);/* printf("\nChanging to header_state\n"); */} return FUNCTION_BLOCK;
       
  1083 PROGRAM{st_whitespace}			if (get_preparse_state()) BEGIN(get_pou_name_state); else {BEGIN(header_state);/* printf("\nChanging to header_state\n"); */} return PROGRAM;
       
  1084 CONFIGURATION{st_whitespace}		if (get_preparse_state()) BEGIN(get_pou_name_state); else {BEGIN(config_state);/* printf("\nChanging to config_state\n"); */} return CONFIGURATION;
       
  1085 }
       
  1086 
       
  1087 <get_pou_name_state>{
       
  1088 {identifier}			BEGIN(ignore_pou_state); yylval.ID=strdup(yytext); return identifier_token;
       
  1089 .				BEGIN(ignore_pou_state); unput_text(0);
       
  1090 }
       
  1091 
       
  1092 <ignore_pou_state>{
       
  1093 END_FUNCTION			unput_text(0); BEGIN(INITIAL);
       
  1094 END_FUNCTION_BLOCK		unput_text(0); BEGIN(INITIAL);
       
  1095 END_PROGRAM			unput_text(0); BEGIN(INITIAL);
       
  1096 END_CONFIGURATION		unput_text(0); BEGIN(INITIAL);
       
  1097 .|\n				{}/* Ignore text inside POU! (including the '\n' character!)) */
       
  1098 }
       
  1099 
       
  1100 
       
  1101 	/* header_state -> (vardecl_list_state) */
       
  1102 	/* NOTE: This transition assumes that all POUs with code (Function, FB, and Program) will always contain
       
  1103 	 *       at least one VAR_XXX block.
       
  1104 	 *      How about functions that do not declare variables, and go directly to the body_state???
  1074 	 *      - According to Section 2.5.1.3 (Function Declaration), item 2 in the list, a FUNCTION
  1105 	 *      - According to Section 2.5.1.3 (Function Declaration), item 2 in the list, a FUNCTION
  1075 	 *        must have at least one input argument, so a correct declaration will have at least
  1106 	 *        must have at least one input argument, so a correct declaration will have at least
  1076 	 *        one VAR_INPUT ... VAR_END construct!
  1107 	 *        one VAR_INPUT ... VAR_END construct!
  1077 	 *      - According to Section 2.5.2.2 (Function Block Declaration), a FUNCTION_BLOCK
  1108 	 *      - According to Section 2.5.2.2 (Function Block Declaration), a FUNCTION_BLOCK
  1078 	 *        must have at least one input argument, so a correct declaration will have at least
  1109 	 *        must have at least one input argument, so a correct declaration will have at least
  1082 	 *        construct!
  1113 	 *        construct!
  1083 	 *
  1114 	 *
  1084 	 *       All the above means that we needn't worry about PROGRAMs, FUNCTIONs or
  1115 	 *       All the above means that we needn't worry about PROGRAMs, FUNCTIONs or
  1085 	 *       FUNCTION_BLOCKs that do not have at least one VAR_END before the body_state.
  1116 	 *       FUNCTION_BLOCKs that do not have at least one VAR_END before the body_state.
  1086 	 *       If the code has an error, and no VAR_END before the body, we will simply
  1117 	 *       If the code has an error, and no VAR_END before the body, we will simply
  1087 	 *       continue in the <vardecl_state> state, untill the end of the FUNCTION, FUNCTION_BLOCK
  1118 	 *       continue in the <vardecl_state> state, until the end of the FUNCTION, FUNCTION_BLOCK
  1088 	 *       or PROGAM.
  1119 	 *       or PROGAM.
       
  1120 	 * 
       
  1121 	 * WARNING: From 2016-05 (May 2016) onwards, matiec supports a non-standard option in which a Function
       
  1122 	 *          may be declared with no Input, Output or IN_OUT variables. This means that the above 
       
  1123 	 *          assumption is no longer valid.
       
  1124 	 *          To make things simpler (i.e. so we do not need to change the transition conditions in the flex state machine),
       
  1125 	 *          when using this non-standard extension matiec requires that Functions must include at least one 
       
  1126 	 *          VAR .. END_VAR block. This implies that the above assumption remains valid!
       
  1127 	 *          This limitation of requiring a VAR .. END_VAR block is not really very limiting, as a function
       
  1128 	 *          with no input and output parameters will probably need to do some 'work', and for that it will
       
  1129 	 *          probably need some local variables declared in a VAR .. END_VAR block.
       
  1130 	 *          Note however that in the extreme it might make sense to have a function with no variables whatsoever
       
  1131 	 *          (e.g.: a function that only calls other functions that all return VOID - another non standard extension!).
       
  1132 	 *          For now we do not consider this!!
  1089 	 */
  1133 	 */
  1090 
       
  1091 FUNCTION{st_whitespace} 		if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION;
       
  1092 FUNCTION_BLOCK{st_whitespace}		if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION_BLOCK;
       
  1093 PROGRAM{st_whitespace}			if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return PROGRAM;
       
  1094 CONFIGURATION{st_whitespace}		if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(config_state); return CONFIGURATION;
       
  1095 }
       
  1096 
       
  1097 <get_pou_name_state>{
       
  1098 {identifier}			BEGIN(ignore_pou_state); yylval.ID=strdup(yytext); return identifier_token;
       
  1099 .				BEGIN(ignore_pou_state); unput_text(0);
       
  1100 }
       
  1101 
       
  1102 <ignore_pou_state>{
       
  1103 END_FUNCTION			unput_text(0); BEGIN(INITIAL);
       
  1104 END_FUNCTION_BLOCK		unput_text(0); BEGIN(INITIAL); 
       
  1105 END_PROGRAM			unput_text(0); BEGIN(INITIAL); 
       
  1106 END_CONFIGURATION		unput_text(0); BEGIN(INITIAL); 
       
  1107 .|\n				{}/* Ignore text inside POU! (including the '\n' character!)) */
       
  1108 }
       
  1109 
       
  1110 	/* INITIAL -> body_state */
       
  1111 	/* required if the function, program, etc.. has no VAR block! */
       
  1112 	/* We comment it out since the standard does not allow this.  */
       
  1113 	/* NOTE: Even if we were to include the following code, it    */
       
  1114 	/*       would have no effect whatsoever since the above      */
       
  1115 	/*       rules will take precendence!                         */
       
  1116 	/*
       
  1117 <INITIAL>{
       
  1118 FUNCTION	BEGIN(body_state); return FUNCTION;
       
  1119 FUNCTION_BLOCK	BEGIN(body_state); return FUNCTION_BLOCK;
       
  1120 PROGRAM		BEGIN(body_state); return PROGRAM;
       
  1121 }
       
  1122 	*/
       
  1123 
       
  1124 	/* header_state -> (vardecl_list_state) */
       
  1125 <header_state>{
  1134 <header_state>{
  1126 VAR				| /* execute the next rule's action, i.e. fall-through! */
  1135 VAR				| /* execute the next rule's action, i.e. fall-through! */
  1127 VAR_INPUT			|
  1136 VAR_INPUT			|
  1128 VAR_OUTPUT			|
  1137 VAR_OUTPUT			|
  1129 VAR_IN_OUT			|
  1138 VAR_IN_OUT			|
  1130 VAR_EXTERNAL			|
  1139 VAR_EXTERNAL			|
  1131 VAR_GLOBAL			|
  1140 VAR_GLOBAL			|
  1132 VAR_TEMP			|
  1141 VAR_TEMP			|
  1133 VAR_CONFIG			|
  1142 VAR_CONFIG			|
  1134 VAR_ACCESS			unput_text(0); BEGIN(vardecl_list_state);
  1143 VAR_ACCESS			unput_text(0); /* printf("\nChanging to vardecl_list_state\n") */; BEGIN(vardecl_list_state);
  1135 }
  1144 }
  1136 
  1145 
  1137 
  1146 
  1138 	/* vardecl_list_state -> (vardecl_state | body_state | INITIAL) */
  1147 	/* vardecl_list_state -> (vardecl_state | body_state | INITIAL) */
  1139 <vardecl_list_state>{
  1148 <vardecl_list_state>{
  1145 VAR_TEMP			|
  1154 VAR_TEMP			|
  1146 VAR_CONFIG			|
  1155 VAR_CONFIG			|
  1147 VAR_ACCESS			|
  1156 VAR_ACCESS			|
  1148 VAR				unput_text(0); yy_push_state(vardecl_state);
  1157 VAR				unput_text(0); yy_push_state(vardecl_state);
  1149 
  1158 
  1150 END_FUNCTION			unput_text(0); BEGIN(INITIAL); 
  1159 END_FUNCTION			unput_text(0); BEGIN(INITIAL);
  1151 END_FUNCTION_BLOCK		unput_text(0); BEGIN(INITIAL); 
  1160 END_FUNCTION_BLOCK		unput_text(0); BEGIN(INITIAL);
  1152 END_PROGRAM			unput_text(0); BEGIN(INITIAL); 
  1161 END_PROGRAM			unput_text(0); BEGIN(INITIAL);
  1153 
  1162 
  1154 .				unput_text(0); yy_push_state(body_state); /* anything else, just change to body_state! */
  1163 .				unput_text(0); yy_push_state(body_state); //printf("\nChanging to body_state\n");/* anything else, just change to body_state! */
  1155 }
  1164 }
  1156 
  1165 
  1157 
  1166 
  1158 	/* vardecl_list_state -> pop to $previous_state (vardecl_list_state) */
  1167 	/* vardecl_list_state -> pop to $previous_state (vardecl_list_state) */
  1159 <vardecl_state>{
  1168 <vardecl_state>{
  1161 }
  1170 }
  1162 
  1171 
  1163 
  1172 
  1164 	/* body_state -> (il_state | st_state | sfc_state) */
  1173 	/* body_state -> (il_state | st_state | sfc_state) */
  1165 <body_state>{
  1174 <body_state>{
  1166 INITIAL_STEP			unput_text(0); BEGIN(sfc_state); 
  1175 {st_whitespace}			{/* In body state we do not process any tokens,
  1167 
  1176 				  * we simply store them for later processing!
  1168 {qualified_identifier}		unput_text(0); BEGIN(st_state); /* will always be followed by '[' for an array access, or ':=' as the left hand of an assignment statement */
  1177 				  * NOTE: all whitespace in the begining
  1169 {direct_variable_standard}	unput_text(0); BEGIN(st_state); /* will always be followed by ':=' as the left hand of an assignment statement */
  1178 				  * of body_state must be removed so we can
  1170 
  1179 				  * detect ':=' in the beginning of TRANSACTION
  1171 RETURN				unput_text(0); BEGIN(st_state);
  1180 				  * conditions preceded by whitespace.
  1172 IF				unput_text(0); BEGIN(st_state);
  1181 				  * => only add to bodystate_buffer when not in beginning.
  1173 CASE				unput_text(0); BEGIN(st_state);
  1182 				  */
  1174 FOR				unput_text(0); BEGIN(st_state);
  1183 				  if (!isempty_bodystate_buffer()) 
  1175 WHILE				unput_text(0); BEGIN(st_state);
  1184 				    append_bodystate_buffer(yytext); 
  1176 EXIT				unput_text(0); BEGIN(st_state);
  1185 				}
  1177 REPEAT				unput_text(0); BEGIN(st_state);
  1186 	/* 'INITIAL_STEP' always used in beginning of SFCs !! */
  1178 
  1187 INITIAL_STEP			{ if (isempty_bodystate_buffer())	{unput_text(0); BEGIN(sfc_state);}
  1179 	/* ':=' occurs only in transitions, and not Function or FB bodies! */
  1188 				  else					{append_bodystate_buffer(yytext);}
  1180 :=				unput_text(0); BEGIN(st_state);
  1189 				}
  1181 
  1190  
  1182 {identifier}	{int token = get_identifier_token(yytext);
  1191 	/* ':=', at the very beginning of a 'body', occurs only in transitions and not Function, FB, or Program bodies! */
  1183 		 if ((token == prev_declared_fb_name_token) || (token == prev_declared_variable_name_token)) {
  1192 :=				{ if (isempty_bodystate_buffer())	{unput_text(0); BEGIN(st_state);} /* We do _not_ return a start_ST_body_token here, as bison does not expect it! */
  1184 		   /* the code has a call to a function block OR has an assingment with a variable as the lvalue */
  1193 				  else				 	{append_bodystate_buffer(yytext);}
  1185 		   unput_text(0); BEGIN(st_state);
  1194 				}
  1186 		 } else
  1195  
  1187  		 if (token == prev_declared_derived_function_name_token) {
  1196 	/* check if ';' occurs before an END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM or END_ACTION. (If true => we are parsing ST; If false => parsing IL). */
  1188 		   /* the code has a call to a function - must be IL */
  1197 END_ACTION			| /* execute the next rule's action, i.e. fall-through! */
  1189 		   unput_text(0); BEGIN(il_state);
  1198 END_FUNCTION			|
  1190 		 } else {
  1199 END_FUNCTION_BLOCK		|
  1191 		   /* Might be a lable in IL, or a bug in ST/IL code. We jump to IL */
  1200 END_PROGRAM			{ append_bodystate_buffer(yytext); unput_bodystate_buffer(); BEGIN(il_state); /*printf("returning start_IL_body_token\n");*/ return start_IL_body_token;}
  1192 		   unput_text(0); BEGIN(il_state);
  1201 .|\n				{ append_bodystate_buffer(yytext);
  1193 		 }
  1202 				  if (strcmp(yytext, ";") == 0)
  1194 		}
  1203 				    {unput_bodystate_buffer(); BEGIN(st_state); /*printf("returning start_ST_body_token\n");*/ return start_ST_body_token;}
  1195 
  1204 				}
  1196 .		unput_text(0); BEGIN(il_state); /* Don't know what it could be. This is most likely a bug. Let's just to a random state... */
  1205 	/* The following rules are not really necessary. They just make compilation faster in case the ST Statement List starts with one fot he following... */
       
  1206 RETURN				| /* execute the next rule's action, i.e. fall-through! */
       
  1207 IF				|
       
  1208 CASE				|
       
  1209 FOR				|
       
  1210 WHILE				|
       
  1211 EXIT				|
       
  1212 REPEAT				{ if (isempty_bodystate_buffer())	{unput_text(0); BEGIN(st_state); return start_ST_body_token;}
       
  1213 				  else				 	{append_bodystate_buffer(yytext);}
       
  1214 				}
       
  1215 
  1197 }	/* end of body_state lexical parser */
  1216 }	/* end of body_state lexical parser */
  1198 
       
  1199 
  1217 
  1200 
  1218 
  1201 	/* (il_state | st_state) -> pop to $previous_state (vardecl_list_state or sfc_state) */
  1219 	/* (il_state | st_state) -> pop to $previous_state (vardecl_list_state or sfc_state) */
  1202 <il_state,st_state>{
  1220 <il_state,st_state>{
  1203 END_FUNCTION		yy_pop_state(); unput_text(0);
  1221 END_FUNCTION		yy_pop_state(); unput_text(0);
  1223 	/* Next is to to remove all whitespace */
  1241 	/* Next is to to remove all whitespace */
  1224 	/***************************************/
  1242 	/***************************************/
  1225 	/* NOTE: pragmas are handled right at the beginning... */
  1243 	/* NOTE: pragmas are handled right at the beginning... */
  1226 
  1244 
  1227 	/* The whitespace */
  1245 	/* The whitespace */
  1228 <INITIAL,header_state,config_state,body_state,vardecl_list_state,vardecl_state,st_state,sfc_state,task_init_state,sfc_qualifier_state>{st_whitespace}	/* Eat any whitespace */
  1246 <INITIAL,header_state,config_state,vardecl_list_state,vardecl_state,st_state,sfc_state,task_init_state,sfc_qualifier_state>{st_whitespace}	/* Eat any whitespace */
  1229 <il_state>{il_whitespace}		/* Eat any whitespace */
  1247 <il_state>{il_whitespace}		/* Eat any whitespace */
       
  1248  /* NOTE: Due to the need of having the following rule have higher priority,
       
  1249   *        the following rule was moved to an earlier position in this file.
       
  1250 <body_state>{st_whitespace}		{...}
       
  1251  */
  1230 
  1252 
  1231 	/* The comments */
  1253 	/* The comments */
  1232 <get_pou_name_state,ignore_pou_state,body_state,vardecl_list_state>{comment_beg}		yy_push_state(comment_state);
  1254 <get_pou_name_state,ignore_pou_state,body_state,vardecl_list_state>{comment_beg}		yy_push_state(comment_state);
  1233 {comment_beg}						yy_push_state(comment_state);
  1255 {comment_beg}						yy_push_state(comment_state);
  1234 <comment_state>{
  1256 <comment_state>{
  1263 	 *       If we don't, then even it will not be possible to use 'MOD'
  1285 	 *       If we don't, then even it will not be possible to use 'MOD'
  1264 	 *       as a funtion as in 'X := MOD(Y, Z);'
  1286 	 *       as a funtion as in 'X := MOD(Y, Z);'
  1265 	 *       We solve this by NOT testing for function names here, and
  1287 	 *       We solve this by NOT testing for function names here, and
  1266 	 *       handling this function and keyword clash in bison!
  1288 	 *       handling this function and keyword clash in bison!
  1267 	 */
  1289 	 */
       
  1290 	/* NOTE: The following code has been commented out as most users do not want matiec
       
  1291 	 *       to allow the use of 'R1', 'IN' ... IL operators as identifiers, 
       
  1292 	 *       even though a literal reading of the standard allows this.
       
  1293 	 *       We could add this as a commadnd line option, but it is not yet done.
       
  1294 	 *       For now we just comment out the code, but leave it the commented code
       
  1295 	 *       in so we can re-activate quickly (without having to go through old commits
       
  1296 	 *       in the mercurial repository to figure out the missing code!
       
  1297 	 */
  1268  /*
  1298  /*
  1269 {identifier} 	{int token = get_identifier_token(yytext);
  1299 {identifier} 	{int token = get_identifier_token(yytext);
  1270 		 // fprintf(stderr, "flex: analysing identifier '%s'...", yytext); 
  1300 		 // fprintf(stderr, "flex: analysing identifier '%s'...", yytext); 
  1271 		 if ((token == prev_declared_variable_name_token) ||
  1301 		 if ((token == prev_declared_variable_name_token) ||
  1272 //		     (token == prev_declared_derived_function_name_token) || // DO NOT add this condition!
  1302 //		     (token == prev_declared_derived_function_name_token) || // DO NOT add this condition!
  1376 DT		return DT;		/* Keyword (Data Type) */
  1406 DT		return DT;		/* Keyword (Data Type) */
  1377 TOD		return TOD;		/* Keyword (Data Type) */
  1407 TOD		return TOD;		/* Keyword (Data Type) */
  1378 DATE_AND_TIME	return DATE_AND_TIME;	/* Keyword (Data Type) */
  1408 DATE_AND_TIME	return DATE_AND_TIME;	/* Keyword (Data Type) */
  1379 TIME_OF_DAY	return TIME_OF_DAY;	/* Keyword (Data Type) */
  1409 TIME_OF_DAY	return TIME_OF_DAY;	/* Keyword (Data Type) */
  1380 
  1410 
       
  1411 					/* A non-standard extension! */
       
  1412 VOID		{if (runtime_options.allow_void_datatype) {return VOID;}          else {REJECT;}} 
       
  1413 
       
  1414 
  1381 	/*****************************************************************/
  1415 	/*****************************************************************/
  1382 	/* Keywords defined in "Safety Software Technical Specification" */
  1416 	/* Keywords defined in "Safety Software Technical Specification" */
  1383 	/*****************************************************************/
  1417 	/*****************************************************************/
  1384         /* 
  1418         /* 
  1385          * NOTE: The following keywords are define in 
  1419          * NOTE: The following keywords are define in 
  1478 
  1512 
  1479 
  1513 
  1480 	/***********************/
  1514 	/***********************/
  1481 	/* B 1.5.1 - Functions */
  1515 	/* B 1.5.1 - Functions */
  1482 	/***********************/
  1516 	/***********************/
  1483 FUNCTION	return FUNCTION;	/* Keyword */
  1517 	/* Note: The following END_FUNCTION rule includes a BEGIN(INITIAL); command.
  1484 END_FUNCTION	return END_FUNCTION;	/* Keyword */
  1518 	 *       This is necessary in case the input program being parsed has syntax errors that force
  1485 VAR		return VAR;		/* Keyword */
  1519 	 *       flex's main state machine to never change to the il_state or the st_state
  1486 CONSTANT	return CONSTANT;	/* Keyword */
  1520 	 *       after changing to the body_state.
       
  1521 	 *       Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with 
       
  1522 	 *       the input stream even in the presence of buggy code!
       
  1523 	 */
       
  1524 FUNCTION			return FUNCTION;			/* Keyword */
       
  1525 END_FUNCTION	BEGIN(INITIAL);	return END_FUNCTION;			/* Keyword */  /* see Note above */
       
  1526 VAR				return VAR;				/* Keyword */
       
  1527 CONSTANT			return CONSTANT;			/* Keyword */
  1487 
  1528 
  1488 
  1529 
  1489 	/*****************************/
  1530 	/*****************************/
  1490 	/* B 1.5.2 - Function Blocks */
  1531 	/* B 1.5.2 - Function Blocks */
  1491 	/*****************************/
  1532 	/*****************************/
  1492 FUNCTION_BLOCK		return FUNCTION_BLOCK;		/* Keyword */
  1533 	/* Note: The following END_FUNCTION_BLOCK rule includes a BEGIN(INITIAL); command.
  1493 END_FUNCTION_BLOCK	return END_FUNCTION_BLOCK;	/* Keyword */
  1534 	 *       This is necessary in case the input program being parsed has syntax errors that force
  1494 VAR_TEMP		return VAR_TEMP;		/* Keyword */
  1535 	 *       flex's main state machine to never change to the il_state or the st_state
  1495 VAR			return VAR;			/* Keyword */
  1536 	 *       after changing to the body_state.
  1496 NON_RETAIN		return NON_RETAIN;		/* Keyword */
  1537 	 *       Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with 
  1497 END_VAR			return END_VAR;			/* Keyword */
  1538 	 *       the input stream even in the presence of buggy code!
       
  1539 	 */
       
  1540 FUNCTION_BLOCK				return FUNCTION_BLOCK;		/* Keyword */
       
  1541 END_FUNCTION_BLOCK	BEGIN(INITIAL);	return END_FUNCTION_BLOCK;	/* Keyword */  /* see Note above */
       
  1542 VAR_TEMP				return VAR_TEMP;		/* Keyword */
       
  1543 VAR					return VAR;			/* Keyword */
       
  1544 NON_RETAIN				return NON_RETAIN;		/* Keyword */
       
  1545 END_VAR					return END_VAR;			/* Keyword */
  1498 
  1546 
  1499 
  1547 
  1500 	/**********************/
  1548 	/**********************/
  1501 	/* B 1.5.3 - Programs */
  1549 	/* B 1.5.3 - Programs */
  1502 	/**********************/
  1550 	/**********************/
  1503 PROGRAM		return PROGRAM;			/* Keyword */
  1551 	/* Note: The following END_PROGRAM rule includes a BEGIN(INITIAL); command.
  1504 END_PROGRAM	return END_PROGRAM;		/* Keyword */
  1552 	 *       This is necessary in case the input program being parsed has syntax errors that force
       
  1553 	 *       flex's main state machine to never change to the il_state or the st_state
       
  1554 	 *       after changing to the body_state.
       
  1555 	 *       Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with 
       
  1556 	 *       the input stream even in the presence of buggy code!
       
  1557 	 */
       
  1558 PROGRAM				return PROGRAM;				/* Keyword */
       
  1559 END_PROGRAM	BEGIN(INITIAL);	return END_PROGRAM;			/* Keyword */  /* see Note above */
  1505 
  1560 
  1506 
  1561 
  1507 	/********************************************/
  1562 	/********************************************/
  1508 	/* B 1.6 Sequential Function Chart elements */
  1563 	/* B 1.6 Sequential Function Chart elements */
  1509 	/********************************************/
  1564 	/********************************************/
  1547 
  1602 
  1548 
  1603 
  1549 	/********************************/
  1604 	/********************************/
  1550 	/* B 1.7 Configuration elements */
  1605 	/* B 1.7 Configuration elements */
  1551 	/********************************/
  1606 	/********************************/
  1552 CONFIGURATION		return CONFIGURATION;		/* Keyword */
  1607 	/* Note: The following END_CONFIGURATION rule will never get to be used, as we have
  1553 END_CONFIGURATION	return END_CONFIGURATION;	/* Keyword */
  1608 	 *       another identical rule above (closer to the rules handling the transitions
  1554 TASK			return TASK;			/* Keyword */
  1609 	 *       of the main state machine) that will always execute before this one.
  1555 RESOURCE		return RESOURCE;		/* Keyword */
  1610 	 * Note: The following END_CONFIGURATION rule includes a BEGIN(INITIAL); command.
  1556 ON			return ON;			/* Keyword */
  1611 	 *       This is nt strictly necessary, but I place it here so it follwos the same
  1557 END_RESOURCE		return END_RESOURCE;		/* Keyword */
  1612 	 *       pattern used in END_FUNCTION, END_PROGRAM, and END_FUNCTION_BLOCK
  1558 VAR_CONFIG		return VAR_CONFIG;		/* Keyword */
  1613 	 */
  1559 VAR_ACCESS		return VAR_ACCESS;		/* Keyword */
  1614 CONFIGURATION				return CONFIGURATION;		/* Keyword */
  1560 END_VAR			return END_VAR;			/* Keyword */
  1615 END_CONFIGURATION	BEGIN(INITIAL); return END_CONFIGURATION;	/* Keyword */   /* see 2 Notes above! */
  1561 WITH			return WITH;			/* Keyword */
  1616 TASK					return TASK;			/* Keyword */
  1562 PROGRAM			return PROGRAM;			/* Keyword */
  1617 RESOURCE				return RESOURCE;		/* Keyword */
  1563 RETAIN			return RETAIN;			/* Keyword */
  1618 ON					return ON;			/* Keyword */
  1564 NON_RETAIN		return NON_RETAIN;		/* Keyword */
  1619 END_RESOURCE				return END_RESOURCE;		/* Keyword */
  1565 READ_WRITE		return READ_WRITE;		/* Keyword */
  1620 VAR_CONFIG				return VAR_CONFIG;		/* Keyword */
  1566 READ_ONLY		return READ_ONLY;		/* Keyword */
  1621 VAR_ACCESS				return VAR_ACCESS;		/* Keyword */
       
  1622 END_VAR					return END_VAR;			/* Keyword */
       
  1623 WITH					return WITH;			/* Keyword */
       
  1624 PROGRAM					return PROGRAM;			/* Keyword */
       
  1625 RETAIN					return RETAIN;			/* Keyword */
       
  1626 NON_RETAIN				return NON_RETAIN;		/* Keyword */
       
  1627 READ_WRITE				return READ_WRITE;		/* Keyword */
       
  1628 READ_ONLY				return READ_ONLY;		/* Keyword */
  1567 
  1629 
  1568 	/* PRIORITY, SINGLE and INTERVAL are not a keywords, so we only return them when 
  1630 	/* PRIORITY, SINGLE and INTERVAL are not a keywords, so we only return them when 
  1569 	 * it is explicitly required and we are not expecting any identifiers
  1631 	 * it is explicitly required and we are not expecting any identifiers
  1570 	 * that could also use the same letter sequence (i.e. an identifier: piority, ...)
  1632 	 * that could also use the same letter sequence (i.e. an identifier: piority, ...)
  1571 	 */
  1633 	 */
  2011   free(yycopy);
  2073   free(yycopy);
  2012 }
  2074 }
  2013 
  2075 
  2014 
  2076 
  2015 
  2077 
       
  2078 /* The body_state tries to find a ';' before a END_PROGRAM, END_FUNCTION or END_FUNCTION_BLOCK or END_ACTION
       
  2079  * To do so, it must ignore comments and pragmas. This means that we cannot do this in a signle lex rule.
       
  2080  * However, we must store any text we consume in every rule, so we can push it back into the buffer
       
  2081  * once we have decided if we are parsing ST or IL code. The following functions manage that buffer used by
       
  2082  * the body_state.
       
  2083  */
       
  2084 /* The buffer used by the body_state state */
       
  2085 char *bodystate_buffer = NULL;
       
  2086 
       
  2087 /* append text to bodystate_buffer */
       
  2088 void  append_bodystate_buffer(const char *text) {
       
  2089   //printf("<<<append_bodystate_buffer>>> %d <%s><%s>\n", bodystate_buffer, text, (NULL != bodystate_buffer)?bodystate_buffer:"NULL");
       
  2090   long int old_len = 0;
       
  2091   if (NULL != bodystate_buffer) old_len = strlen(bodystate_buffer);
       
  2092   bodystate_buffer = (char *)realloc(bodystate_buffer, old_len + strlen(text) + 1);
       
  2093   if (NULL == bodystate_buffer) ERROR;
       
  2094   strcpy(bodystate_buffer + old_len, text);
       
  2095   //printf("=<%s> %d %d\n", (NULL != bodystate_buffer)?bodystate_buffer:NULL, old_len + strlen(text) + 1, bodystate_buffer);
       
  2096 }
       
  2097 
       
  2098 /* Return all data in bodystate_buffer back to flex, and empty bodystate_buffer. */
       
  2099 void   unput_bodystate_buffer(void) {
       
  2100   if (NULL == bodystate_buffer) ERROR;
       
  2101   //printf("<<<unput_bodystate_buffer>>>\n%s\n", bodystate_buffer);
       
  2102   
       
  2103   for (long int i = strlen(bodystate_buffer)-1; i >= 0; i--)
       
  2104     unput(bodystate_buffer[i]);
       
  2105   
       
  2106   free(bodystate_buffer);
       
  2107   bodystate_buffer = NULL;
       
  2108 }
       
  2109 
       
  2110 
       
  2111 /* Return true if bodystate_buffer is empty */
       
  2112 int  isempty_bodystate_buffer(void) {
       
  2113   return (NULL == bodystate_buffer);
       
  2114 }
       
  2115 
       
  2116 
       
  2117 
       
  2118 
  2016 /* Called by flex when it reaches the end-of-file */
  2119 /* Called by flex when it reaches the end-of-file */
  2017 int yywrap(void)
  2120 int yywrap(void)
  2018 {
  2121 {
  2019   /* We reached the end of the input file... */
  2122   /* We reached the end of the input file... */
  2020 
  2123