142 * where the value of the tokens will be stored |
142 * where the value of the tokens will be stored |
143 */ |
143 */ |
144 extern YYSTYPE yylval; |
144 extern YYSTYPE yylval; |
145 |
145 |
146 /* The name of the file currently being parsed... |
146 /* The name of the file currently being parsed... |
147 * This variable is declared and read from the code generated by bison! |
|
148 * Note that flex accesses and updates this global variable |
147 * Note that flex accesses and updates this global variable |
149 * apropriately whenever it comes across an (*#include <filename> *) |
148 * apropriately whenever it comes across an (*#include <filename> *) directive... |
150 * directive... |
149 */ |
151 */ |
150 const char *current_filename = NULL; |
152 /* |
151 |
153 NOTE: already defined in iec_bison.h |
|
154 extern const char *current_filename; |
|
155 */ |
|
156 |
152 |
157 |
153 |
158 /* We will not be using unput() in our flex code... */ |
154 /* We will not be using unput() in our flex code... */ |
159 /* NOTE: it seems that this #define is no longer needed, It has been |
155 /* NOTE: it seems that this #define is no longer needed, It has been |
160 * replaced by %option nounput. |
156 * replaced by %option nounput. |
247 * but first return to the stream an additional character to mark the end of the token. |
243 * but first return to the stream an additional character to mark the end of the token. |
248 */ |
244 */ |
249 void unput_and_mark(const char c); |
245 void unput_and_mark(const char c); |
250 |
246 |
251 void include_file(const char *include_filename); |
247 void include_file(const char *include_filename); |
|
248 |
|
249 int GetNextChar(char *b, int maxBuffer); |
252 %} |
250 %} |
253 |
251 |
254 |
252 |
255 |
253 |
256 /****************************/ |
254 /****************************/ |
464 |
462 |
465 %{ |
463 %{ |
466 #define MAX_INCLUDE_DEPTH 16 |
464 #define MAX_INCLUDE_DEPTH 16 |
467 |
465 |
468 typedef struct { |
466 typedef struct { |
|
467 int eof; |
|
468 int lineNumber; |
|
469 int currentChar; |
|
470 int lineLength; |
|
471 int currentTokenStart; |
|
472 char *buffer; |
|
473 FILE *in_file; |
|
474 } tracking_t; |
|
475 |
|
476 typedef struct { |
469 YY_BUFFER_STATE buffer_state; |
477 YY_BUFFER_STATE buffer_state; |
470 tracking_t* env; |
478 tracking_t *env; |
471 const char *filename; |
479 const char *filename; |
472 } include_stack_t; |
480 } include_stack_t; |
473 |
481 |
474 tracking_t* current_tracking; |
482 tracking_t *current_tracking = NULL; |
475 include_stack_t include_stack[MAX_INCLUDE_DEPTH]; |
483 include_stack_t include_stack[MAX_INCLUDE_DEPTH]; |
476 int include_stack_ptr = 0; |
484 int include_stack_ptr = 0; |
477 |
485 |
478 const char *INCLUDE_DIRECTORIES[] = { |
486 const char *INCLUDE_DIRECTORIES[] = { |
479 DEFAULT_LIBDIR, |
487 DEFAULT_LIBDIR, |
883 * If we have finished parsing the main file, then we |
890 * If we have finished parsing the main file, then we |
884 * must leave include_stack_ptr at 0, in case the |
891 * must leave include_stack_ptr at 0, in case the |
885 * parser is called once again with a new file. |
892 * parser is called once again with a new file. |
886 * (In fact, we currently do just that!) |
893 * (In fact, we currently do just that!) |
887 */ |
894 */ |
|
895 fclose(yyin); |
888 free(current_tracking); |
896 free(current_tracking); |
889 if (include_stack_ptr == 0) { |
897 if (include_stack_ptr == 0) { |
890 /* yyterminate() terminates the scanner and returns a 0 to the |
898 /* yyterminate() terminates the scanner and returns a 0 to the |
891 * scanner's caller, indicating "all done". |
899 * scanner's caller, indicating "all done". |
892 * |
900 * |
982 } |
990 } |
983 |
991 |
984 /* body_state -> (il_state | st_state) */ |
992 /* body_state -> (il_state | st_state) */ |
985 <body_state>{ |
993 <body_state>{ |
986 {st_whitespace_no_pragma} /* Eat any whitespace */ |
994 {st_whitespace_no_pragma} /* Eat any whitespace */ |
987 {qualified_identifier}{st_whitespace}":=" unput_text(0); BEGIN(st_state); |
995 {qualified_identifier}{st_whitespace}":=" unput_text(0); BEGIN(st_state); |
988 {direct_variable_standard}{st_whitespace}":=" unput_text(0); BEGIN(st_state); |
996 {direct_variable_standard}{st_whitespace}":=" unput_text(0); BEGIN(st_state); |
989 {qualified_identifier}"[" unput_text(0); BEGIN(st_state); |
997 {qualified_identifier}"[" unput_text(0); BEGIN(st_state); |
990 |
998 |
991 RETURN unput_text(0); BEGIN(st_state); |
999 RETURN unput_text(0); BEGIN(st_state); |
992 IF unput_text(0); BEGIN(st_state); |
1000 IF unput_text(0); BEGIN(st_state); |
993 CASE unput_text(0); BEGIN(st_state); |
1001 CASE unput_text(0); BEGIN(st_state); |
994 FOR unput_text(0); BEGIN(st_state); |
1002 FOR unput_text(0); BEGIN(st_state); |
995 WHILE unput_text(0); BEGIN(st_state); |
1003 WHILE unput_text(0); BEGIN(st_state); |
996 REPEAT unput_text(0); BEGIN(st_state); |
1004 REPEAT unput_text(0); BEGIN(st_state); |
997 EXIT unput_text(0); BEGIN(st_state); |
1005 EXIT unput_text(0); BEGIN(st_state); |
998 |
1006 |
999 /* ':=' occurs only in transitions, and not Function or FB bodies! */ |
1007 /* ':=' occurs only in transitions, and not Function or FB bodies! */ |
1000 := unput_text(0); BEGIN(st_state); |
1008 := unput_text(0); BEGIN(st_state); |
1001 |
1009 |
1002 /* Hopefully, the above rules (along with the last one), |
1010 /* Hopefully, the above rules (along with the last one), |
1003 * used to distinguish ST from IL, are |
1011 * used to distinguish ST from IL, are |
1004 * enough to handle all ocurrences. However, if |
1012 * enough to handle all ocurrences. However, if |
1005 * there is some situation where the compiler is getting confused, |
1013 * there is some situation where the compiler is getting confused, |
1647 |
1655 |
1648 |
1656 |
1649 %% |
1657 %% |
1650 |
1658 |
1651 |
1659 |
|
1660 /*************************/ |
|
1661 /* Tracking Functions... */ |
|
1662 /*************************/ |
|
1663 |
|
1664 #define MAX_BUFFER_LENGTH 1000 |
|
1665 |
|
1666 tracking_t *GetNewTracking(FILE* in_file) { |
|
1667 tracking_t* new_env = new tracking_t; |
|
1668 new_env->eof = 0; |
|
1669 new_env->lineNumber = 0; |
|
1670 new_env->currentChar = 0; |
|
1671 new_env->lineLength = 0; |
|
1672 new_env->currentTokenStart = 0; |
|
1673 new_env->buffer = (char*)malloc(MAX_BUFFER_LENGTH); |
|
1674 new_env->in_file = in_file; |
|
1675 return new_env; |
|
1676 } |
|
1677 |
|
1678 |
|
1679 /* GetNextChar: reads a character from input */ |
|
1680 int GetNextChar(char *b, int maxBuffer) { |
|
1681 char *p; |
|
1682 |
|
1683 if ( current_tracking->eof ) |
|
1684 return 0; |
|
1685 |
|
1686 while ( current_tracking->currentChar >= current_tracking->lineLength ) { |
|
1687 current_tracking->currentChar = 0; |
|
1688 current_tracking->currentTokenStart = 1; |
|
1689 current_tracking->eof = false; |
|
1690 |
|
1691 p = fgets(current_tracking->buffer, MAX_BUFFER_LENGTH, current_tracking->in_file); |
|
1692 if ( p == NULL ) { |
|
1693 if ( ferror(current_tracking->in_file) ) |
|
1694 return 0; |
|
1695 current_tracking->eof = true; |
|
1696 return 0; |
|
1697 } |
|
1698 |
|
1699 current_tracking->lineNumber++; |
|
1700 current_tracking->lineLength = strlen(current_tracking->buffer); |
|
1701 } |
|
1702 |
|
1703 b[0] = current_tracking->buffer[current_tracking->currentChar]; |
|
1704 if (b[0] == ' ' || b[0] == '\t') |
|
1705 current_tracking->currentTokenStart++; |
|
1706 current_tracking->currentChar++; |
|
1707 |
|
1708 return b[0]==0?0:1; |
|
1709 } |
|
1710 |
|
1711 |
|
1712 |
|
1713 |
1652 /***********************************/ |
1714 /***********************************/ |
1653 /* Utility function definitions... */ |
1715 /* Utility function definitions... */ |
1654 /***********************************/ |
1716 /***********************************/ |
1655 |
1717 |
1656 /* print the include file stack to stderr... */ |
1718 /* print the include file stack to stderr... */ |
1689 |
1751 |
1690 |
1752 |
1691 /* insert the code (in <source_code>) into the source code we are parsing. |
1753 /* insert the code (in <source_code>) into the source code we are parsing. |
1692 * This is done by creating an artificial file with that new source code, and then 'including' the file |
1754 * This is done by creating an artificial file with that new source code, and then 'including' the file |
1693 */ |
1755 */ |
1694 void include_string(const char *source_code) { |
1756 void include_string_(const char *source_code) { |
1695 FILE *tmp_file = tmpfile(); |
1757 FILE *tmp_file = tmpfile(); |
1696 |
1758 |
1697 if(tmp_file == NULL) { |
1759 if(tmp_file == NULL) { |
1698 perror("Error creating temp file."); |
1760 perror("Error creating temp file."); |
1699 exit(EXIT_FAILURE); |
1761 exit(EXIT_FAILURE); |
1788 return 1; /* Stop scanning at end of input file. */ |
1850 return 1; /* Stop scanning at end of input file. */ |
1789 } |
1851 } |
1790 |
1852 |
1791 |
1853 |
1792 |
1854 |
|
1855 /*******************************/ |
|
1856 /* Public Interface for Bison. */ |
|
1857 /*******************************/ |
|
1858 |
|
1859 /* The following functions will be called from inside bison code! */ |
|
1860 |
|
1861 void include_string(const char *source_code) {include_string_(source_code);} |
|
1862 |
|
1863 |
|
1864 /* Tell flex which file to parse. This function will not imediately start parsing the file. |
|
1865 * To parse the file, you then need to call yyparse() |
|
1866 * |
|
1867 * Returns -1 on error opening the file (and a valid errno), or 0 on success. |
|
1868 */ |
|
1869 int parse_file(const char *filename) { |
|
1870 FILE *filehandle = NULL; |
|
1871 |
|
1872 if((filehandle = fopen(filename, "r")) == NULL) |
|
1873 return -1; |
|
1874 |
|
1875 yyin = filehandle; |
|
1876 current_filename = strdup(filename); |
|
1877 current_tracking = GetNewTracking(yyin); |
|
1878 return 0; |
|
1879 } |
|
1880 |
|
1881 |
|
1882 |
|
1883 |
|
1884 |
|
1885 |
1793 /*************************************/ |
1886 /*************************************/ |
1794 /* Include a main() function to test */ |
1887 /* Include a main() function to test */ |
1795 /* the token parsing by flex.... */ |
1888 /* the token parsing by flex.... */ |
1796 /*************************************/ |
1889 /*************************************/ |
1797 #ifdef TEST_MAIN |
1890 #ifdef TEST_MAIN |