176 /* Macro that is executed for every action. |
176 /* Macro that is executed for every action. |
177 * We use it to pass the location of the token |
177 * We use it to pass the location of the token |
178 * back to the bison parser... |
178 * back to the bison parser... |
179 */ |
179 */ |
180 #define YY_USER_ACTION {\ |
180 #define YY_USER_ACTION {\ |
181 yylloc.first_line = current_tracking->lineNumber; \ |
181 previous_tracking =*current_tracking; \ |
182 yylloc.first_column = current_tracking->currentTokenStart; \ |
182 yylloc.first_line = current_tracking->lineNumber; \ |
183 yylloc.first_file = current_filename; \ |
183 yylloc.first_column = current_tracking->currentChar; \ |
184 yylloc.first_order = current_order; \ |
184 yylloc.first_file = current_filename; \ |
185 yylloc.last_line = current_tracking->lineNumber; \ |
185 yylloc.first_order = current_order; \ |
186 yylloc.last_column = current_tracking->currentChar - 1; \ |
186 \ |
187 yylloc.last_file = current_filename; \ |
187 UpdateTracking(yytext); \ |
188 yylloc.last_order = current_order; \ |
188 \ |
|
189 yylloc.last_line = current_tracking->lineNumber; \ |
|
190 yylloc.last_column = current_tracking->currentChar - 1; \ |
|
191 yylloc.last_file = current_filename; \ |
|
192 yylloc.last_order = current_order; \ |
|
193 \ |
189 current_tracking->currentTokenStart = current_tracking->currentChar; \ |
194 current_tracking->currentTokenStart = current_tracking->currentChar; \ |
190 current_order++; \ |
195 current_order++; \ |
191 } |
196 } |
192 |
|
193 |
197 |
194 |
198 |
195 /* Since this lexical parser we defined only works in ASCII based |
199 /* Since this lexical parser we defined only works in ASCII based |
196 * systems, we might as well make sure it is being compiled on |
200 * systems, we might as well make sure it is being compiled on |
197 * one... |
201 * one... |
220 /***************************************************/ |
224 /***************************************************/ |
221 /* Forward Declaration of functions defined later. */ |
225 /* Forward Declaration of functions defined later. */ |
222 /***************************************************/ |
226 /***************************************************/ |
223 |
227 |
224 %{ |
228 %{ |
|
229 void UpdateTracking(const char *text); |
|
230 /* return the character back to the input stream. */ |
|
231 void unput_char(const char c); |
225 /* return all the text in the current token back to the input stream. */ |
232 /* return all the text in the current token back to the input stream. */ |
226 void unput_text(unsigned int n); |
233 void unput_text(int n); |
227 /* return all the text in the current token back to the input stream, |
234 /* return all the text in the current token back to the input stream, |
228 * but first return to the stream an additional character to mark the end of the token. |
235 * but first return to the stream an additional character to mark the end of the token. |
229 */ |
236 */ |
230 void unput_and_mark(const char c); |
237 void unput_and_mark(const char mark_char); |
231 |
238 |
232 void include_file(const char *include_filename); |
239 void include_file(const char *include_filename); |
233 |
240 |
234 /* The body_state tries to find a ';' before a END_PROGRAM, END_FUNCTION or END_FUNCTION_BLOCK or END_ACTION |
241 /* The body_state tries to find a ';' before a END_PROGRAM, END_FUNCTION or END_FUNCTION_BLOCK or END_ACTION |
235 * To do so, it must ignore comments and pragmas. This means that we cannot do this in a signle lex rule. |
242 * and ignores ';' inside comments and pragmas. This means that we cannot do this in a signle lex rule. |
236 * However, we must store any text we consume in every rule, so we can push it back into the buffer |
243 * Body_state therefore stores ALL text we consume in every rule, so we can push it back into the buffer |
237 * once we have decided if we are parsing ST or IL code. The following functions manage that buffer used by |
244 * once we have decided if we are parsing ST or IL code. The following functions manage that buffer used by |
238 * the body_state. |
245 * the body_state. |
239 */ |
246 */ |
240 void append_bodystate_buffer(const char *yytext); |
247 void append_bodystate_buffer(const char *text); |
241 void unput_bodystate_buffer(void); |
248 void unput_bodystate_buffer(void); |
242 int isempty_bodystate_buffer(void); |
249 int isempty_bodystate_buffer(void); |
243 |
250 |
244 int GetNextChar(char *b, int maxBuffer); |
251 int GetNextChar(char *b, int maxBuffer); |
245 %} |
252 %} |
1177 |
1192 |
1178 /* body_state -> (il_state | st_state | sfc_state) */ |
1193 /* body_state -> (il_state | st_state | sfc_state) */ |
1179 <body_state>{ |
1194 <body_state>{ |
1180 {st_whitespace} {/* In body state we do not process any tokens, |
1195 {st_whitespace} {/* In body state we do not process any tokens, |
1181 * we simply store them for later processing! |
1196 * we simply store them for later processing! |
1182 * NOTE: all whitespace in the begining |
1197 * NOTE: we must return ALL text when in body_state, including |
1183 * of body_state must be removed so we can |
1198 * all comments and whitespace, so as not |
1184 * detect ':=' in the beginning of TRANSACTION |
1199 * to lose track of the line_number and column number |
1185 * conditions preceded by whitespace. |
1200 * used when printing debugging messages. |
1186 * => only add to bodystate_buffer when not in beginning. |
1201 * Note that some of the following rules depend on the fact that |
|
1202 * the body state buffer is either empty or only contains white space up to |
|
1203 * that point. However, since the vardecl_list_state will eat up all |
|
1204 * whitespace before entering the body_state, the contents of the bodystate_buffer |
|
1205 * will _never_ start with whitespace. |
1187 */ |
1206 */ |
1188 if (!isempty_bodystate_buffer()) |
1207 append_bodystate_buffer(yytext); |
1189 append_bodystate_buffer(yytext); |
|
1190 } |
1208 } |
1191 /* 'INITIAL_STEP' always used in beginning of SFCs !! */ |
1209 /* 'INITIAL_STEP' always used in beginning of SFCs !! */ |
1192 INITIAL_STEP { if (isempty_bodystate_buffer()) {unput_text(0); BEGIN(sfc_state);} |
1210 INITIAL_STEP { if (isempty_bodystate_buffer()) {unput_text(0); BEGIN(sfc_state);} |
1193 else {append_bodystate_buffer(yytext);} |
1211 else {append_bodystate_buffer(yytext);} |
1194 } |
1212 } |
1901 |
1919 |
1902 #define MAX_LINE_LENGTH 1024 |
1920 #define MAX_LINE_LENGTH 1024 |
1903 |
1921 |
1904 tracking_t *GetNewTracking(FILE* in_file) { |
1922 tracking_t *GetNewTracking(FILE* in_file) { |
1905 tracking_t* new_env = new tracking_t; |
1923 tracking_t* new_env = new tracking_t; |
1906 new_env->eof = 0; |
1924 new_env->eof = 0; |
1907 new_env->lineNumber = 0; |
1925 new_env->lineNumber = 1; |
1908 new_env->currentChar = 0; |
1926 new_env->currentChar = 0; |
1909 new_env->lineLength = 0; |
1927 new_env->lineLength = 0; |
1910 new_env->currentTokenStart = 0; |
1928 new_env->currentTokenStart = 0; |
1911 new_env->buffer = (char*)malloc(MAX_LINE_LENGTH); |
|
1912 new_env->in_file = in_file; |
1929 new_env->in_file = in_file; |
1913 return new_env; |
1930 return new_env; |
1914 } |
1931 } |
1915 |
1932 |
1916 |
1933 |
1917 void FreeTracking(tracking_t *tracking) { |
1934 void FreeTracking(tracking_t *tracking) { |
1918 free(tracking->buffer); |
|
1919 delete tracking; |
1935 delete tracking; |
|
1936 } |
|
1937 |
|
1938 |
|
1939 void UpdateTracking(const char *text) { |
|
1940 const char *newline, *token = text; |
|
1941 while ((newline = strchr(token, '\n')) != NULL) { |
|
1942 token = newline + 1; |
|
1943 current_tracking->lineNumber++; |
|
1944 current_tracking->currentChar = 1; |
|
1945 } |
|
1946 current_tracking->currentChar += strlen(token); |
1920 } |
1947 } |
1921 |
1948 |
1922 |
1949 |
1923 /* GetNextChar: reads a character from input */ |
1950 /* GetNextChar: reads a character from input */ |
1924 int GetNextChar(char *b, int maxBuffer) { |
1951 int GetNextChar(char *b, int maxBuffer) { |
1925 char *p; |
1952 int res = fgetc(current_tracking->in_file); |
1926 |
1953 if ( res == EOF ) |
1927 if ( current_tracking->eof ) |
|
1928 return 0; |
1954 return 0; |
1929 |
1955 *b = (char)res; |
1930 while ( current_tracking->currentChar >= current_tracking->lineLength ) { |
1956 return 1; |
1931 current_tracking->currentChar = 0; |
1957 } |
1932 current_tracking->currentTokenStart = 1; |
|
1933 current_tracking->eof = false; |
|
1934 |
|
1935 p = fgets(current_tracking->buffer, MAX_LINE_LENGTH, current_tracking->in_file); |
|
1936 if ( p == NULL ) { |
|
1937 if ( ferror(current_tracking->in_file) ) |
|
1938 return 0; |
|
1939 current_tracking->eof = true; |
|
1940 return 0; |
|
1941 } |
|
1942 |
|
1943 current_tracking->lineLength = strlen(current_tracking->buffer); |
|
1944 |
|
1945 /* only increment line number if the buffer was big enough to read the whole line! */ |
|
1946 char last_char = current_tracking->buffer[current_tracking->lineLength - 1]; |
|
1947 if (('\n' == last_char) || ('\r' == last_char)) // '\r' ---> CR, '\n' ---> LF |
|
1948 current_tracking->lineNumber++; |
|
1949 } |
|
1950 |
|
1951 b[0] = current_tracking->buffer[current_tracking->currentChar]; |
|
1952 if (b[0] == ' ' || b[0] == '\t') |
|
1953 current_tracking->currentTokenStart++; |
|
1954 current_tracking->currentChar++; |
|
1955 |
|
1956 return b[0]==0?0:1; |
|
1957 } |
|
1958 |
|
1959 |
1958 |
1960 |
1959 |
1961 |
1960 |
1962 /***********************************/ |
1961 /***********************************/ |
1963 /* Utility function definitions... */ |
1962 /* Utility function definitions... */ |
2043 handle_include_file_(filehandle, filename); |
2042 handle_include_file_(filehandle, filename); |
2044 } |
2043 } |
2045 |
2044 |
2046 |
2045 |
2047 |
2046 |
|
2047 /* return the specified character to the input stream */ |
|
2048 /* WARNING: this function destroys the contents of yytext */ |
|
2049 void unput_char(const char c) { |
|
2050 /* NOTE: The following uncomented code is not necessary as we currently use a different algorithm: |
|
2051 * - make a backup/snapshot of the current tracking data (in previous_tracking variable) |
|
2052 * (done in YY_USER_ACTION) |
|
2053 * - restore the previous tracking state when we unput any text... |
|
2054 * (in unput_text() and unput_and_mark() ) |
|
2055 */ |
|
2056 // /* We will later be processing this same character again when it is read from the input strem, |
|
2057 // * and therefore we will be incrementing the line number and character column acordingly. |
|
2058 // * We must therefore try to 'undo' the changes to the line number and character column |
|
2059 // * so this character is not counted twice! |
|
2060 // */ |
|
2061 // if (c == '\n') { |
|
2062 // current_tracking->lineNumber--; |
|
2063 // /* We should now set the current_tracking->currentChar to the length of the previous line |
|
2064 // * But we currently have no way of knowing it, so we simply set it to 0. |
|
2065 // * I (msousa) don't think this is currently an issue because I don't believe the code |
|
2066 // * ever calls unput_char() with a '\n', so we leave it for now |
|
2067 // */ |
|
2068 // current_tracking->currentChar = 0; |
|
2069 // } else if (current_tracking->currentChar > 0) { |
|
2070 // current_tracking->currentChar--; |
|
2071 // } |
|
2072 |
|
2073 unput(c); // unput() destroys the contents of yytext !! |
|
2074 } |
2048 |
2075 |
2049 |
2076 |
2050 /* return all the text in the current token back to the input stream, except the first n chars. */ |
2077 /* return all the text in the current token back to the input stream, except the first n chars. */ |
2051 void unput_text(unsigned int n) { |
2078 void unput_text(int n) { |
2052 /* it seems that flex has a bug in that it will not correctly count the line numbers |
2079 if (n < 0) ERROR; |
2053 * if we return newlines back to the input stream. These newlines will be re-counted |
2080 signed int i; // must be signed! The iterartion may end with -1 when this function is called with n=0 !! |
2054 * a second time when they are processed again by flex. |
2081 |
2055 * We therefore determine how many newlines are in the text we are returning, |
2082 char *yycopy = strdup( yytext ); /* unput_char() destroys yytext, so we copy it first */ |
2056 * and decrement the line counter acordingly... |
2083 for (int i = yyleng-1; i >= n; i--) |
2057 */ |
2084 unput_char(yycopy[i]); |
2058 /* |
2085 |
2059 unsigned int i; |
2086 *current_tracking = previous_tracking; |
|
2087 yycopy[n] = '\0'; |
|
2088 UpdateTracking(yycopy); |
2060 |
2089 |
2061 for (i = n; i < strlen(yytext); i++) |
2090 free(yycopy); |
2062 if (yytext[i] == '\n') |
2091 } |
2063 current_tracking->lineNumber--; |
2092 |
2064 */ |
|
2065 /* now return all the text back to the input stream... */ |
|
2066 yyless(n); |
|
2067 } |
|
2068 |
2093 |
2069 |
2094 |
2070 /* return all the text in the current token back to the input stream, |
2095 /* return all the text in the current token back to the input stream, |
2071 * but first return to the stream an additional character to mark the end of the token. |
2096 * but first return to the stream an additional character to mark the end of the token. |
2072 */ |
2097 */ |
2073 void unput_and_mark(const char c) { |
2098 void unput_and_mark(const char mark_char) { |
2074 char *yycopy = strdup( yytext ); /* unput() destroys yytext, so we copy it first */ |
2099 char *yycopy = strdup( yytext ); /* unput_char() destroys yytext, so we copy it first */ |
2075 unput(c); |
2100 unput_char(mark_char); |
2076 for (int i = yyleng-1; i >= 0; i--) |
2101 for (int i = yyleng-1; i >= 0; i--) |
2077 unput(yycopy[i]); |
2102 unput_char(yycopy[i]); |
2078 |
2103 |
2079 free(yycopy); |
2104 free(yycopy); |
|
2105 *current_tracking = previous_tracking; |
2080 } |
2106 } |
2081 |
2107 |
2082 |
2108 |
2083 |
2109 |
2084 /* The body_state tries to find a ';' before a END_PROGRAM, END_FUNCTION or END_FUNCTION_BLOCK or END_ACTION |
2110 /* The body_state tries to find a ';' before a END_PROGRAM, END_FUNCTION or END_FUNCTION_BLOCK or END_ACTION |
2085 * To do so, it must ignore comments and pragmas. This means that we cannot do this in a signle lex rule. |
2111 * and ignores ';' inside comments and pragmas. This means that we cannot do this in a signle lex rule. |
2086 * However, we must store any text we consume in every rule, so we can push it back into the buffer |
2112 * Body_state therefore stores ALL text we consume in every rule, so we can push it back into the buffer |
2087 * once we have decided if we are parsing ST or IL code. The following functions manage that buffer used by |
2113 * once we have decided if we are parsing ST or IL code. The following functions manage that buffer used by |
2088 * the body_state. |
2114 * the body_state. |
2089 */ |
2115 */ |
2090 /* The buffer used by the body_state state */ |
2116 /* The buffer used by the body_state state */ |
2091 char *bodystate_buffer = NULL; |
2117 char *bodystate_buffer = NULL; |
|
2118 bool bodystate_is_whitespace = 1; // TRUE (1) if buffer is empty, or only contains whitespace. |
|
2119 tracking_t bodystate_init_tracking; |
2092 |
2120 |
2093 /* append text to bodystate_buffer */ |
2121 /* append text to bodystate_buffer */ |
2094 void append_bodystate_buffer(const char *text) { |
2122 void append_bodystate_buffer(const char *text) { |
2095 //printf("<<<append_bodystate_buffer>>> %d <%s><%s>\n", bodystate_buffer, text, (NULL != bodystate_buffer)?bodystate_buffer:"NULL"); |
2123 // printf("<<<append_bodystate_buffer>>> %d <%s><%s>\n", bodystate_buffer, text, (NULL != bodystate_buffer)?bodystate_buffer:"NULL"); |
2096 long int old_len = 0; |
2124 long int old_len = 0; |
|
2125 // make backup of tracking if we are starting off a new body_state_buffer |
|
2126 if (NULL == bodystate_buffer) bodystate_init_tracking = *current_tracking; |
|
2127 |
2097 if (NULL != bodystate_buffer) old_len = strlen(bodystate_buffer); |
2128 if (NULL != bodystate_buffer) old_len = strlen(bodystate_buffer); |
2098 bodystate_buffer = (char *)realloc(bodystate_buffer, old_len + strlen(text) + 1); |
2129 bodystate_buffer = (char *)realloc(bodystate_buffer, old_len + strlen(text) + 1); |
2099 if (NULL == bodystate_buffer) ERROR; |
2130 if (NULL == bodystate_buffer) ERROR; |
2100 strcpy(bodystate_buffer + old_len, text); |
2131 strcpy(bodystate_buffer + old_len, text); |
2101 //printf("=<%s> %d %d\n", (NULL != bodystate_buffer)?bodystate_buffer:NULL, old_len + strlen(text) + 1, bodystate_buffer); |
2132 //printf("=<%s> %d %d\n", (NULL != bodystate_buffer)?bodystate_buffer:NULL, old_len + strlen(text) + 1, bodystate_buffer); |
2102 } |
2133 } |
2103 |
2134 |
2104 /* Return all data in bodystate_buffer back to flex, and empty bodystate_buffer. */ |
2135 /* Return all data in bodystate_buffer back to flex, and empty bodystate_buffer. */ |
2105 void unput_bodystate_buffer(void) { |
2136 void unput_bodystate_buffer(void) { |
2106 if (NULL == bodystate_buffer) ERROR; |
2137 if (NULL == bodystate_buffer) ERROR; |
2107 //printf("<<<unput_bodystate_buffer>>>\n%s\n", bodystate_buffer); |
2138 // printf("<<<unput_bodystate_buffer>>>\n%s\n", bodystate_buffer); |
2108 |
2139 |
2109 for (long int i = strlen(bodystate_buffer)-1; i >= 0; i--) |
2140 for (long int i = strlen(bodystate_buffer)-1; i >= 0; i--) |
2110 unput(bodystate_buffer[i]); |
2141 unput_char(bodystate_buffer[i]); |
2111 |
2142 |
2112 free(bodystate_buffer); |
2143 free(bodystate_buffer); |
2113 bodystate_buffer = NULL; |
2144 bodystate_buffer = NULL; |
2114 } |
2145 *current_tracking = bodystate_init_tracking; |
2115 |
2146 } |
2116 |
2147 |
2117 /* Return true if bodystate_buffer is empty */ |
2148 |
|
2149 /* Return true if bodystate_buffer is empty or ony contains whitespace!! */ |
2118 int isempty_bodystate_buffer(void) { |
2150 int isempty_bodystate_buffer(void) { |
2119 return (NULL == bodystate_buffer); |
2151 if (NULL == bodystate_buffer) return 1; |
|
2152 return 0; |
2120 } |
2153 } |
2121 |
2154 |
2122 |
2155 |
2123 |
2156 |
2124 |
2157 |