diff options
Diffstat (limited to 'src/parser/parser.l')
| -rw-r--r-- | src/parser/parser.l | 218 |
1 files changed, 173 insertions, 45 deletions
diff --git a/src/parser/parser.l b/src/parser/parser.l index 3edda2f..3519d0d 100644 --- a/src/parser/parser.l +++ b/src/parser/parser.l @@ -12,39 +12,54 @@ BIN_OPERATOR [,=\*/\+\-\^] PAR_OPERATOR [\{\}\(\)\[\]<>] OPERATOR {BIN_OPERATOR}|{PAR_OPERATOR}|{BIDIR_SPECIFIER} - WS [ \t] WS_BREAK (?:[^{WS}]) /* EOL_DOS \r\n */ /* EOL_UNIX \n */ -/* EOL_OLD_MAC \n */ +/* EOL_OLD_MAC \r */ EOL_PORTABLE \r?\n EOL {EOL_PORTABLE} %option warn %option yylineno -/*%option noyywrap*/ +%option noyywrap %option caseless %option reentrant %option bison-bridge %option stack +%option extra-type="void *" %{ #include <string> #include <sstream> // for conversions of numbers from str #include <cstring> // for strcpy #include <vector> +#include <deque> #include "parse_tree.h" +#include "parser_state.h" #include "parser.tab.h" using std::string; using std::vector; +using std::deque; + +typedef struct { + enum type { + NETLIST_FILE, + STRING + } type; + string description; + YY_BUFFER_STATE buf; + FILE *fp = nullptr; +} netlist_content_t; + +deque<netlist_content_t> netlist_content_fifo; #define YY_NO_INPUT #define YY_NO_UNPUT -#define YY_EXTRA_TYPE void* +#define YY_EXTRA_TYPE void * YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size, yyscan_t scanner); void yypush_buffer_state ( YY_BUFFER_STATE buffer, yyscan_t scanner); @@ -54,12 +69,120 @@ int yyget_column ( yyscan_t scanner ); void yyset_extra ( YY_EXTRA_TYPE user_defined, yyscan_t scanner ); YY_EXTRA_TYPE yyget_extra ( yyscan_t scanner ); +string yyget_filename ( yyscan_t scanner ); +string yyget_current_line ( yyscan_t scanner ); + +string yyget_filename ( yyscan_t scanner ) +{ + const ParserState *yy_extra = (ParserState *)yyget_extra(scanner); + return yy_extra->current_filename; +} + +void yyset_filename (string fname, yyscan_t scanner) +{ + ParserState *yy_extra = (ParserState *)yyget_extra(scanner); + yy_extra->current_filename = fname; +} + +string yyget_current_line ( yyscan_t scanner ) +{ + const ParserState *yy_extra = (ParserState *)yyget_extra(scanner); + return yy_extra->current_line; +} + +void yyset_current_line (string line_content, yyscan_t scanner) +{ + ParserState *yy_extra = (ParserState *)yyget_extra(scanner); + yy_extra->current_line = line_content; +} + +int yy_load_next_buf(yyscan_t scanner) +{ + static FILE *last_file = nullptr; + + if ( last_file ) + { + fclose(last_file); + } + + if (netlist_content_fifo.empty()) + { + yyset_filename("-"s, scanner); + return 1; + } + else + { + auto netlist_content = netlist_content_fifo.front(); + netlist_content_fifo.pop_front(); + + string filename = netlist_content.description; + if (netlist_content.type == netlist_content_t::STRING) + filename = "[autogenerated - " + filename + "]"; + yyset_filename(filename, scanner); + yy_switch_to_buffer(netlist_content.buf, scanner); + + last_file = netlist_content.fp; + return 0; + } +} + +void yy_add_content_from_string(const string &str, const string &desc, yyscan_t &scanner) +{ + // Allocate memory for the string (c-style) + // necessary as flex will delete the buffer + char* cstr = new char[str.size() + 1]; + + // Copy the contents of the std::string to the new memory + std::strcpy(cstr, str.c_str()); + + netlist_content_t netlist_content; + + netlist_content.type = netlist_content_t::STRING; + netlist_content.description = desc; + netlist_content.buf = yy_scan_string(cstr, scanner); + netlist_content.fp = nullptr; + netlist_content_fifo.push_back(netlist_content); +} + +void yy_add_content_from_file(const string &filename, yyscan_t &scanner) +{ + // Check whether the file exists + FILE *f; + if (filename == "-"s) { + cerr << "Error: stdin not supported." << endl; + exit(1); + } else if (!(f = fopen(filename.c_str(), "r"))) { + cerr << "Error: File not found \"" << filename << "\"" << endl; + exit(1); + } + + netlist_content_t netlist_content; + + { + stringstream ss; + ss << endl << "*** START of " << filename << " ***" << endl; + yy_add_content_from_string(ss.str(), "header for " + filename, scanner); + } + + netlist_content.type = netlist_content_t::NETLIST_FILE; + netlist_content.description = filename; + netlist_content.buf = yy_create_buffer(f, YY_BUF_SIZE, scanner); + netlist_content.fp = f; + netlist_content_fifo.push_back(netlist_content); + + { + stringstream ss; + ss << endl << "*** END of " << filename << " ***" << endl; + yy_add_content_from_string(ss.str(), "footer for " + filename, scanner); + } +} + int yylerror(yyscan_t scanner, const char *p) { - cerr << "error (line " << yyget_lineno(scanner) << "): " << p << endl; - string * str = (string *)yyget_extra(scanner); - if (str) - cerr << "\twhile parsing line: " << *str << endl; + cerr << "Parsing error (" << yyget_filename(scanner) << ":" << yyget_lineno(scanner) << "): " << p << endl; + string str = yyget_current_line(scanner); + if (!str.empty()) + cerr << "-- while parsing line: \"" << str << "\"" << endl; return 3; } @@ -77,6 +200,30 @@ static T from_string(const string &str) return ret; } +string convert_special_char(char c) +{ + stringstream ss; + switch (c) + { + case '\r': + ss << "\\r"; + break; + case '\n': + ss << "\\n"; + break; + case '\t': + ss << "\\t"; + break; + case '\b': + ss << "\\b"; + break; + default: + ss << c; + break; + } + return ss.str(); +} + %} /*** States ***/ @@ -93,14 +240,9 @@ static T from_string(const string &str) %% /*** Rules section ***/ -^.*{EOL} { - // print the netlist as it is read - // note: doesnt handle included files - if(false) - cout << yytext; REJECT; +<INITIAL,SUBCKT_DEFINITION>^\.include { + yy_push_state(INCLUDE, yyscanner); } - -^\.include {yy_push_state(INCLUDE, yyscanner);} <INCLUDE>{WS}* /* eat the whitespace */ <INCLUDE>[^ ;\t\n\r]+ { /* got the include file name */ yyin = fopen( yytext, "r" ); @@ -326,7 +468,7 @@ static T from_string(const string &str) } <INITIAL>^\.ENDS { - cerr << "Unexpeced '.ENDS' directive" << endl; + cerr << "unexpected '.ENDS' directive" << endl; exit(1); } @@ -363,12 +505,10 @@ static T from_string(const string &str) {WS} ; -^.*/{EOL} { - string * str = (string *)yyget_extra(yyscanner); - if (!str) - str = new string; - *str = yytext; - yyset_extra((void *)str, yyscanner); +<*>^.*/{EOL} { + yyset_current_line(yytext, yyscanner); + if (false) + cout << yytext << endl; REJECT; } @@ -387,41 +527,29 @@ static T from_string(const string &str) {EOL} { return '\n'; } -<INITIAL,INCLUDE><<EOF>> { + +<INITIAL><<EOF>> { yypop_buffer_state(yyscanner); if ( !YY_CURRENT_BUFFER ) { - yyterminate(); + if ( ! yy_load_next_buf(yyscanner) ) + return '\n'; + else + yyterminate(); } return '\n'; } -<SUBCKT_DECLARATION,IN_DQUOTES><<EOF>> { - exit(yylerror(yyscanner, "Unexpected end of file.")); +<SUBCKT_DECLARATION,IN_DQUOTES,INCLUDE><<EOF>> { + exit(yylerror(yyscanner, "unexpected end of file.")); } <*>. { stringstream msg; - msg << "Unexpected character: \""; - switch (yytext[0]) - { - case '\r': - msg << "\\r"; - break; - case '\n': - msg << "\\n"; - break; - case '\t': - msg << "\\t"; - break; - case '\b': - msg << "\\b"; - break; - default: - msg << yytext[0]; - break; - } + char c = yytext[0]; + msg << "unexpected character: \""; + msg << convert_special_char(c); msg << "\""; exit(yylerror(yyscanner, msg.str().c_str())); } |
