diff options
| -rw-r--r-- | src/main.cpp | 74 | ||||
| -rw-r--r-- | src/parser/parse_tree.cpp | 5 | ||||
| -rw-r--r-- | src/parser/parser.l | 218 | ||||
| -rw-r--r-- | src/parser/parser.y | 12 | ||||
| -rw-r--r-- | src/parser/parser_state.h | 10 |
5 files changed, 209 insertions, 110 deletions
diff --git a/src/main.cpp b/src/main.cpp index 015648c..96af216 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,6 +16,7 @@ #include <specs.h> #include "optical_output_port.h" #include "parser/parse_tree.h" +#include "parser/parser_state.h" class OpticalOutputPort; @@ -26,54 +27,10 @@ using namespace literals; #include "../build/parser/parser.tab.h" #include "../build/parser/parser.yy.h" extern int yydebug; -int yywrap(yyscan_t scanner); -extern "C" int yy_delete_buffer(yyscan_t scanner); - -static deque<YY_BUFFER_STATE> netlist_buf_fifo; - -FILE* open_netlist_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); - } - - string header = "\n**** START of " + filename + " ****\n"; - netlist_buf_fifo.push_back(yy_scan_string(header.c_str(), scanner)); - - YY_BUFFER_STATE buf = yy_create_buffer(f, YY_BUF_SIZE, scanner); - netlist_buf_fifo.push_back(buf); - - string footer = "\n**** END of " + filename + " ****\n"; - netlist_buf_fifo.push_back(yy_scan_string(footer.c_str(), scanner)); - - return f; -} - -int yywrap(yyscan_t scanner) -{ - static YY_BUFFER_STATE *last_buffer = NULL; - - if (netlist_buf_fifo.empty()) - return 1; - else - { - YY_BUFFER_STATE buf = netlist_buf_fifo.front(); - netlist_buf_fifo.pop_front(); - yy_switch_to_buffer(buf, scanner); - if ( last_buffer ) - { - yy_delete_buffer( *last_buffer, scanner); - last_buffer = &buf; - } - return 0; - } -} +extern int yy_load_next_buf(yyscan_t scanner); +extern void yy_add_content_from_string(const string &str, const string &desc, yyscan_t &scanner); +extern void yy_add_content_from_file(const string &filename, yyscan_t &scanner); +//extern "C" int yy_delete_buffer(yyscan_t scanner); int do_list_tests() { @@ -121,9 +78,10 @@ int do_circuit(const string &filename, bool is_dry_run = false, const string& js cout << "╚═══════════════════╝" << endl; yyscan_t scanner; + ParserState *parser_state = new ParserState; YY_BUFFER_STATE buf; - yylex_init(&scanner); + yylex_init_extra(parser_state, &scanner); buf = yy_create_buffer(f, YY_BUF_SIZE, scanner); yy_switch_to_buffer(buf, scanner); @@ -132,6 +90,7 @@ int do_circuit(const string &filename, bool is_dry_run = false, const string& js //yy_delete_buffer(buf, scanner); yylex_destroy(scanner); + delete parser_state; // Close the file if (f) @@ -184,23 +143,19 @@ int do_circuit(const string &filename, bool is_dry_run = false, const string& js int build_circuit(ParseTree &pt, const vector<string> &filenames, string footer="") { yyscan_t scanner; - yylex_init(&scanner); + yylex_init_extra(new ParserState(), &scanner); - vector<FILE*> files; for(const auto &fname: filenames) - { - FILE * f = open_netlist_file(fname, scanner); - files.push_back(f); - } + yy_add_content_from_file(fname, scanner); // add footer - netlist_buf_fifo.push_back(yy_scan_string(footer.c_str(), scanner)); + yy_add_content_from_string(footer, "footer autogenerated from command line arguments", scanner); // Set up first file - int res = yywrap(scanner); + int res = yy_load_next_buf(scanner); if(res != 0) { - cerr << "Expected yywrap to return 0" << endl; + cerr << "Expected yy_load_next_buf to return 0" << endl; exit(1); } @@ -213,9 +168,6 @@ int build_circuit(ParseTree &pt, const vector<string> &filenames, string footer= //yy_delete_buffer(buf, scanner); yylex_destroy(scanner); - for (auto &f: files) - fclose(f); - // Return if unsuccessful if (parsing_result != 0) { return parsing_result; diff --git a/src/parser/parse_tree.cpp b/src/parser/parse_tree.cpp index 76c67b0..bbafeb8 100644 --- a/src/parser/parse_tree.cpp +++ b/src/parser/parse_tree.cpp @@ -1,6 +1,7 @@ #include "parse_tree.h" #include "parse_directive.h" #include "parse_element.h" +#include "parser_state.h" #include "specs.h" #include <sstream> @@ -310,9 +311,10 @@ ParseTree::ParseTree(const string &name, const ParseSubcircuit &subcircuit, cons } yyscan_t scanner; + ParserState *parser_state = new ParserState; YY_BUFFER_STATE buf; - yylex_init(&scanner); + yylex_init_extra(parser_state, &scanner); buf = yy_scan_string(subcircuit.netlist.c_str(), scanner); yy_switch_to_buffer(buf, scanner); @@ -320,6 +322,7 @@ ParseTree::ParseTree(const string &name, const ParseSubcircuit &subcircuit, cons //yy_delete_buffer(buf, scanner); yylex_destroy(scanner); + delete parser_state; // Return if unsuccessful if (parsing_result != 0) { 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())); } diff --git a/src/parser/parser.y b/src/parser/parser.y index 36be00f..855277e 100644 --- a/src/parser/parser.y +++ b/src/parser/parser.y @@ -10,6 +10,9 @@ //extern int yylineno; //extern char *yytext; + + string yyget_filename ( yyscan_t scanner ); + string yyget_current_line ( yyscan_t scanner ); } %{ @@ -954,8 +957,11 @@ int yyerror(yyscan_t scanner, ParseTree *pt, const char *err) } } string token_escaped = ss.str(); - printf("-- Error in the netlist (line %u): %s\n", yyget_lineno(scanner), err); - printf("-- \"%s\"\n", token_escaped.c_str()); - //cerr << err << endl; + + cerr << "Parsing error (" << yyget_filename(scanner) << ":" << yyget_lineno(scanner) << "): " << err << endl; + cerr << "-- offending token: \"" << token_escaped.c_str() << "\"" << endl; + string str = yyget_current_line(scanner); + if (!str.empty()) + cerr << "-- while parsing line: \"" << str << "\"" << endl; exit(1); } diff --git a/src/parser/parser_state.h b/src/parser/parser_state.h new file mode 100644 index 0000000..359d67f --- /dev/null +++ b/src/parser/parser_state.h @@ -0,0 +1,10 @@ +#pragma once + +#include <string> + +using std::string; + +struct ParserState { + string current_filename; + string current_line; +}; |
