From fb6e7f9fa742157ca1bffcc7f665c2eb7308103b Mon Sep 17 00:00:00 2001 From: James Cherry Date: Mon, 27 Jan 2025 08:33:35 -0700 Subject: [PATCH] liberty parser c++ commit 1abf72bc3430d34a51d82992f1c753f0274a662a Author: James Cherry Date: Mon Jan 27 08:01:04 2025 -0700 rm unused lib visitors Signed-off-by: James Cherry commit 1e76acfc7829a8ba82f96d369fae6225a7361844 Author: James Cherry Date: Sun Jan 26 21:15:46 2025 -0700 verilog/sdf stream->is_open Signed-off-by: James Cherry commit c4a57c0354ffb6c4edfc3269d56a937c11ad9609 Author: James Cherry Date: Sun Jan 26 19:54:41 2025 -0700 leak Signed-off-by: James Cherry commit b992ed1124a862cb04f0c7617a4575f916c3fe01 Author: James Cherry Date: Sun Jan 26 16:39:16 2025 -0700 liberty mv string_buf to scanner Signed-off-by: James Cherry commit 894cbfa5d5b731738dcc60d492689fad9d13bd40 Author: James Cherry Date: Sun Jan 26 16:29:42 2025 -0700 liberty use regex to parse include file Signed-off-by: James Cherry commit 176225849d3fcac0b2be1a5b623270c386daed3d Author: James Cherry Date: Sun Jan 26 15:48:09 2025 -0700 liberty include filename Signed-off-by: James Cherry commit 516e12721d7185015d8c29e8b16fa185f0f46983 Author: James Cherry Date: Sun Jan 26 15:31:18 2025 -0700 liberty include Signed-off-by: James Cherry commit 32098a2159798dfbb80140927949bb36f480093d Author: James Cherry Date: Sun Jan 26 15:01:47 2025 -0700 liberty include Signed-off-by: James Cherry commit 880214e632d756c3199b000fee88fd4fdffac371 Author: James Cherry Date: Sun Jan 26 13:55:02 2025 -0700 liberty include Signed-off-by: James Cherry commit ad1efca842a6d7ee608ffd5a19a69885786b77fa Author: James Cherry Date: Sun Jan 26 10:11:07 2025 -0700 liberty passes all but include Signed-off-by: James Cherry commit e71cf1f39dd09e81cf2b0e5a12dcf51675f2a6fd Author: James Cherry Date: Sun Jan 26 10:01:08 2025 -0700 liberty parser use class compiles Signed-off-by: James Cherry commit 02dea0ff753b0fa12f280661a46e2c0ef2432357 Author: James Cherry Date: Sat Jan 25 19:08:06 2025 -0700 liberty parser compiles Signed-off-by: James Cherry Signed-off-by: James Cherry --- CMakeLists.txt | 18 +- liberty/LibertyLex.ll | 132 ++++------ liberty/LibertyParse.yy | 87 ++++--- liberty/LibertyParser.cc | 490 +++++++++++++++++------------------- liberty/LibertyParser.hh | 94 +++---- liberty/LibertyReader.cc | 34 ++- liberty/LibertyReaderPvt.hh | 29 +-- liberty/LibertyScanner.hh | 74 ++++++ sdf/SdfParse.yy | 2 - sdf/SdfReader.cc | 17 +- sdf/SdfReaderPvt.hh | 4 +- sdf/SdfScanner.hh | 6 +- util/gzstream.hh | 3 +- verilog/VerilogReader.cc | 2 +- 14 files changed, 495 insertions(+), 497 deletions(-) create mode 100644 liberty/LibertyScanner.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index 4940f6bc..3bf9dafb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -273,6 +273,15 @@ set(STA_TCL_FILES find_package(FLEX) find_package(BISON) +# Liberty scan/parse. +flex_target(LibertyLex ${STA_HOME}/liberty/LibertyLex.ll + ${CMAKE_CURRENT_BINARY_DIR}/LibertyLex.cc) +bison_target(LibertyParse ${STA_HOME}/liberty/LibertyParse.yy + ${CMAKE_CURRENT_BINARY_DIR}/LibertyParse.cc + # centos7 bison 3.0.4 < 3.3.0 uses parser_class_name instead of api.parsr.class + COMPILE_FLAGS "-Wno-deprecated") +add_flex_bison_dependency(LibertyLex LibertyParse) + # LibertyExpr scan/parse. flex_target(LibertyExprLex ${STA_HOME}/liberty/LibertyExprLex.ll ${CMAKE_CURRENT_BINARY_DIR}/LibertyExprLex.cc @@ -283,15 +292,6 @@ bison_target(LibertyExprParse ${STA_HOME}/liberty/LibertyExprParse.yy ) add_flex_bison_dependency(LibertyExprLex LibertyExprParse) -# Liberty scan/parse. -flex_target(LibertyLex ${STA_HOME}/liberty/LibertyLex.ll ${CMAKE_CURRENT_BINARY_DIR}/LibertyLex.cc - COMPILE_FLAGS --prefix=LibertyLex_ - ) -bison_target(LibertyParse ${STA_HOME}/liberty/LibertyParse.yy ${CMAKE_CURRENT_BINARY_DIR}/LibertyParse.cc - COMPILE_FLAGS "--name-prefix=LibertyParse_ -v" - ) -add_flex_bison_dependency(LibertyLex LibertyParse) - # Spef scan/parse. flex_target(SpefLex ${STA_HOME}/parasitics/SpefLex.ll ${CMAKE_CURRENT_BINARY_DIR}/SpefLex.cc COMPILE_FLAGS --prefix=SpefLex_ diff --git a/liberty/LibertyLex.ll b/liberty/LibertyLex.ll index 9acd5c76..1bac5e9f 100644 --- a/liberty/LibertyLex.ll +++ b/liberty/LibertyLex.ll @@ -29,33 +29,29 @@ #include "util/FlexDisableRegister.hh" #include "liberty/LibertyParser.hh" #include "LibertyParse.hh" +#include "liberty/LibertyScanner.hh" -#define YY_NO_INPUT +#undef YY_DECL +#define YY_DECL \ +int \ +sta::LibertyScanner::lex(sta::LibertyParse::semantic_type *const yylval, \ + sta::LibertyParse::location_type *loc) -#if defined(YY_FLEX_MAJOR_VERSION) \ - && defined(YY_FLEX_MINOR_VERSION) \ - && YY_FLEX_MAJOR_VERSION >=2 \ - && (YY_FLEX_MINOR_VERSION > 5 \ - || (YY_FLEX_MINOR_VERSION == 5 \ - && defined(YY_FLEX_SUBMINOR_VERSION) \ - && YY_FLEX_SUBMINOR_VERSION >= 31)) - #define INCLUDE_SUPPORTED -#endif +// update location on matching +#define YY_USER_ACTION loc->step(); loc->columns(yyleng); -static std::string string_buf; - -void -libertyParseFlushBuffer() -{ - YY_FLUSH_BUFFER; -} +typedef sta::LibertyParse::token token; %} -/* %option debug */ +%option c++ +%option yyclass="sta::LibertyScanner" +%option prefix="Liberty" %option noyywrap -%option nounput %option never-interactive +%option stack +%option yylineno +/* %option debug */ %x comment %x qstring @@ -86,21 +82,20 @@ TOKEN_END {PUNCTUATION}|[ \t\r\n] EOL \r?\n %% -{PUNCTUATION} { return ((int) LibertyLex_text[0]); } +{PUNCTUATION} { return ((int) yytext[0]); } {FLOAT}{TOKEN_END} { /* Push back the TOKEN_END character. */ - yyless(LibertyLex_leng - 1); - LibertyParse_lval.number = static_cast(strtod(LibertyLex_text, - NULL)); - return FLOAT; + yyless(yyleng - 1); + yylval->number = strtod(yytext, nullptr); + return token::FLOAT; } {ALPHA}({ALPHA}|_|{DIGIT})*{TOKEN_END} { /* Push back the TOKEN_END character. */ - yyless(LibertyLex_leng - 1); - LibertyParse_lval.string = sta::stringCopy(LibertyLex_text); - return KEYWORD; + yyless(yyleng - 1); + yylval->string = sta::stringCopy(yytext); + return token::KEYWORD; } {PIN_NAME}{TOKEN_END} | @@ -111,106 +106,75 @@ EOL \r?\n {BUS_STYLE}{TOKEN_END} | {TOKEN}{TOKEN_END} { /* Push back the TOKEN_END character. */ - yyless(LibertyLex_leng - 1); - LibertyParse_lval.string = sta::stringCopy(LibertyLex_text); - return STRING; + yyless(yyleng - 1); + yylval->string = sta::stringCopy(yytext); + return token::STRING; } -\\?{EOL} { sta::libertyIncrLine(); } +\\?{EOL} { loc->lines(); loc->step(); } "include_file"[ \t]*"(".+")"[ \t]*";"? { -#ifdef INCLUDE_SUPPORTED - if (sta::libertyInInclude()) - sta::libertyParseError("nested include_file's are not supported"); - else { - char *filename = &yytext[strlen("include_file")]; - /* Skip blanks between include_file and '('. */ - while (isspace(*filename) && *filename != '\0') - filename++; - /* Skip '('. */ - filename++; - /* Skip blanks between '(' and filename. */ - while (isspace(*filename) && *filename != '\0') - filename++; - char *filename_end = strpbrk(filename, ")"); - if (filename_end == NULL) - sta::libertyParseError("include_file missing ')'"); - else { - /* Trim trailing blanks. */ - while (isspace(filename_end[-1]) && filename_end > filename) - filename_end--; - *filename_end = '\0'; - sta::libertyIncludeBegin(filename); - yypush_buffer_state(yy_create_buffer(nullptr, YY_BUF_SIZE)); - BEGIN(INITIAL); - } - } -#else - sta::libertyParseError("include_file is not supported."); -#endif -} + if (includeBegin()) { + BEGIN(INITIAL); + } + } "/*" BEGIN(comment); /* Straight out of the flex man page. */ [^*\r\n]* /* eat anything that's not a '*' */ "*"+[^*/\r\n]* /* eat up '*'s not followed by '/'s */ -{EOL} sta::libertyIncrLine(); +{EOL} { loc->lines(); loc->step(); } "*"+"/" BEGIN(INITIAL); \" { - string_buf.erase(); + token_.clear(); BEGIN(qstring); } \" { BEGIN(INITIAL); - LibertyParse_lval.string = sta::stringCopy(string_buf.c_str()); - return STRING; + yylval->string = stringCopy(token_.c_str()); + return token::STRING; } {EOL} { - LibertyParse_error("unterminated string constant"); + error("unterminated string constant"); BEGIN(INITIAL); - LibertyParse_lval.string = sta::stringCopy(string_buf.c_str()); - return STRING; + yylval->string = stringCopy(token_.c_str()); + return token::STRING; } \\{EOL} { /* Line continuation. */ - sta::libertyIncrLine(); + loc->lines(); loc->step(); } \\. { /* Escaped character. */ - string_buf += '\\'; - string_buf += LibertyLex_text[1]; + token_ += '\\'; + token_ += yytext[1]; } [^\\\r\n\"]+ { /* Anything but escape, return or double quote */ - string_buf += LibertyLex_text; + token_ += yytext; } <> { - LibertyParse_error("unterminated string constant"); + error("unterminated string constant"); BEGIN(INITIAL); yyterminate(); } {BLANK}* {} /* Send out of bound characters to parser. */ -. { return (int) LibertyLex_text[0]; } +. { return (int) yytext[0]; } -<> { -#ifdef INCLUDE_SUPPORTED - if (sta::libertyInInclude()) { - sta::libertyIncludeEnd(); - yypop_buffer_state(); - } - else -#endif - yyterminate(); -} +<> { if (stream_prev_) + fileEnd(); + else + yyterminate(); + } %% diff --git a/liberty/LibertyParse.yy b/liberty/LibertyParse.yy index aba2f65e..df362a2e 100644 --- a/liberty/LibertyParse.yy +++ b/liberty/LibertyParse.yy @@ -1,4 +1,3 @@ -%{ // OpenSTA, Static Timing Analyzer // Copyright (c) 2025, Parallax Software, Inc. // @@ -23,25 +22,41 @@ // // This notice may not be removed or altered from any source distribution. +%{ #include -#include #include "StringUtil.hh" #include "liberty/LibertyParser.hh" +#include "liberty/LibertyScanner.hh" -int LibertyLex_lex(); -#define LibertyParse_lex LibertyLex_lex -// Use yacc generated parser errors. -#define YYERROR_VERBOSE +#undef yylex +#define yylex scanner->lex -#define YYDEBUG 1 +// warning: variable 'yynerrs_' set but not used +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#define loc_line(loc) loc.begin.line %} +%require "3.0" +%skeleton "lalr1.cc" +%debug +%define api.namespace {sta} +%locations +%define parse.assert +%parse-param { LibertyScanner *scanner } +%parse-param { LibertyParser *reader } + +// bison 3.0.4 for centos7 +%define parser_class_name {LibertyParse} +// bison 3.3.2 +//%define api.parser.class {LibertyParse} + +%expect 2 + %union { char *string; float number; - int line; char ch; sta::LibertyAttrValue *attr_value; sta::LibertyAttrValueSeq *attr_values; @@ -61,16 +76,10 @@ int LibertyLex_lex(); %type attr_values %type attr_value %type string expr expr_term expr_term1 volt_expr -%type line %type expr_op volt_op -%expect 2 - %start file -%{ -%} - %% file: @@ -78,26 +87,22 @@ file: ; group: - KEYWORD '(' ')' line '{' - { sta::libertyGroupBegin($1, nullptr, $4); } + KEYWORD '(' ')' '{' + { reader->groupBegin($1, nullptr, loc_line(@1)); } '}' semi_opt - { $$ = sta::libertyGroupEnd(); } -| KEYWORD '(' ')' line '{' - { sta::libertyGroupBegin($1, nullptr, $4); } + { $$ = reader->groupEnd(); } +| KEYWORD '(' ')' '{' + { reader->groupBegin($1, nullptr, loc_line(@1)); } statements '}' semi_opt - { $$ = sta::libertyGroupEnd(); } -| KEYWORD '(' attr_values ')' line '{' - { sta::libertyGroupBegin($1, $3, $5); } + { $$ = reader->groupEnd(); } +| KEYWORD '(' attr_values ')' '{' + { reader->groupBegin($1, $3, loc_line(@1)); } '}' semi_opt - { $$ = sta::libertyGroupEnd(); } -| KEYWORD '(' attr_values ')' line '{' - { sta::libertyGroupBegin($1, $3, $5); } + { $$ = reader->groupEnd(); } +| KEYWORD '(' attr_values ')' '{' + { reader->groupBegin($1, $3, loc_line(@1)); } statements '}' semi_opt - { $$ = sta::libertyGroupEnd(); } - ; - -line: /* empty */ - { $$ = sta::libertyLine(); } + { $$ = reader->groupEnd(); } ; statements: @@ -113,15 +118,15 @@ statement: ; simple_attr: - KEYWORD ':' attr_value line semi_opt - { $$ = sta::makeLibertySimpleAttr($1, $3, $4); } + KEYWORD ':' attr_value semi_opt + { $$ = reader->makeSimpleAttr($1, $3, loc_line(@1)); } ; complex_attr: - KEYWORD '(' ')' line semi_opt - { $$ = sta::makeLibertyComplexAttr($1, nullptr, $4); } -| KEYWORD '(' attr_values ')' line semi_opt - { $$ = sta::makeLibertyComplexAttr($1, $3, $5); } + KEYWORD '(' ')' semi_opt + { $$ = reader->makeComplexAttr($1, nullptr, loc_line(@1)); } +| KEYWORD '(' attr_values ')' semi_opt + { $$ = reader->makeComplexAttr($1, $3, loc_line(@1)); } ; attr_values: @@ -140,8 +145,8 @@ attr_values: ; variable: - string '=' FLOAT line semi_opt - { $$ = sta::makeLibertyVariable($1, $3, $4); } + string '=' FLOAT semi_opt + { $$ = reader->makeVariable($1, $3, loc_line(@1)); } ; string: @@ -153,11 +158,11 @@ string: attr_value: FLOAT - { $$ = sta::makeLibertyFloatAttrValue($1); } + { $$ = reader->makeFloatAttrValue($1); } | expr - { $$ = sta::makeLibertyStringAttrValue($1); } + { $$ = reader->makeStringAttrValue($1); } | volt_expr - { $$ = sta::makeLibertyStringAttrValue($1); } + { $$ = reader->makeStringAttrValue($1); } ; /* Voltage expressions are ignored. */ diff --git a/liberty/LibertyParser.cc b/liberty/LibertyParser.cc index 14ec9c2d..c568aa20 100644 --- a/liberty/LibertyParser.cc +++ b/liberty/LibertyParser.cc @@ -26,106 +26,124 @@ #include #include +#include +#include "Zlib.hh" #include "Report.hh" #include "Error.hh" #include "StringUtil.hh" - -// Global namespace - -int -LibertyParse_parse(); +#include "LibertyScanner.hh" namespace sta { -typedef Vector LibertyGroupSeq; - -static const char *liberty_filename; -static gzFile liberty_stream; -static int liberty_line; -// Previous lex reader state for include files. -static const char *liberty_filename_prev; -static int liberty_line_prev; -static gzFile liberty_stream_prev; - -static LibertyGroupVisitor *liberty_group_visitor; -static LibertyGroupSeq liberty_group_stack; -static Report *liberty_report; - -static LibertyStmt * -makeLibertyDefine(LibertyAttrValueSeq *values, - int line); -static LibertyAttrType -attrValueType(const char *value_type_name); -static LibertyGroupType -groupType(const char *group_type_name); - -//////////////////////////////////////////////////////////////// - void parseLibertyFile(const char *filename, LibertyGroupVisitor *library_visitor, Report *report) { - liberty_stream = gzopen(filename, "r"); - if (liberty_stream) { - liberty_group_visitor = library_visitor; - liberty_group_stack.clear(); - liberty_filename = filename; - liberty_filename_prev = nullptr; - liberty_stream_prev = nullptr; - liberty_line = 1; - liberty_report = report; - LibertyParse_parse(); - gzclose(liberty_stream); + std::istream *stream = new gzstream::igzstream(filename); + if (stream->good()) { + LibertyParser reader(filename, library_visitor, report); + LibertyScanner scanner(stream, filename, &reader, report); + LibertyParse parser(&scanner, &reader); + parser.parse(); + delete stream; + } + else { + delete stream; + throw FileNotReadable(filename); + } +} + +LibertyParser::LibertyParser(const char *filename, + LibertyGroupVisitor *library_visitor, + Report *report) : + filename_(filename), + group_visitor_(library_visitor), + report_(report) +{ +} + +void +LibertyParser::setFilename(const string &filename) +{ + filename_ = filename; +} + +LibertyStmt * +LibertyParser::makeDefine(LibertyAttrValueSeq *values, + int line) +{ + LibertyDefine *define = nullptr; + if (values->size() == 3) { + const char *define_name = (*values)[0]->stringValue(); + const char *group_type_name = (*values)[1]->stringValue(); + const char *value_type_name = (*values)[2]->stringValue(); + LibertyAttrType value_type = attrValueType(value_type_name); + LibertyGroupType group_type = groupType(group_type_name); + define = new LibertyDefine(stringCopy(define_name), group_type, + value_type, line); + LibertyGroup *group = this->group(); + group->addDefine(define); } else - throw FileNotReadable(filename); + report_->fileWarn(24, filename_.c_str(), line, + "define does not have three arguments."); + return define; } -void -libertyGetChars(char *buf, - int &result, - size_t max_size) +// The Liberty User Guide Version 2001.08 fails to define the strings +// used to define valid attribute types. Beyond "string" these are +// guesses. +LibertyAttrType +LibertyParser::attrValueType(const char *value_type_name) { - char *status = gzgets(liberty_stream, buf, max_size); - if (status == Z_NULL) - result = 0; // YY_nullptr + if (stringEq(value_type_name, "string")) + return LibertyAttrType::attr_string; + else if (stringEq(value_type_name, "integer")) + return LibertyAttrType::attr_int; + else if (stringEq(value_type_name, "float")) + return LibertyAttrType::attr_double; + else if (stringEq(value_type_name, "boolean")) + return LibertyAttrType::attr_boolean; else - result = strlen(buf); + return LibertyAttrType::attr_unknown; } -void -libertyGetChars(char *buf, - size_t &result, - size_t max_size) +LibertyGroupType +LibertyParser::groupType(const char *group_type_name) { - char *status = gzgets(liberty_stream, buf, max_size); - if (status == Z_NULL) - result = 0; // YY_nullptr + if (stringEq(group_type_name, "library")) + return LibertyGroupType::library; + else if (stringEq(group_type_name, "cell")) + return LibertyGroupType::cell; + else if (stringEq(group_type_name, "pin")) + return LibertyGroupType::pin; + else if (stringEq(group_type_name, "timing")) + return LibertyGroupType::timing; else - result = strlen(buf); + return LibertyGroupType::unknown; } void -libertyGroupBegin(const char *type, - LibertyAttrValueSeq *params, - int line) +LibertyParser::groupBegin(const char *type, + LibertyAttrValueSeq *params, + int line) { LibertyGroup *group = new LibertyGroup(type, params, line); - liberty_group_visitor->begin(group); - liberty_group_stack.push_back(group); + group_visitor_->begin(group); + group_stack_.push_back(group); } LibertyGroup * -libertyGroupEnd() +LibertyParser::groupEnd() { - LibertyGroup *group = libertyGroup(); - liberty_group_visitor->end(group); - liberty_group_stack.pop_back(); + LibertyGroup *group = this->group(); + group_visitor_->end(group); + group_stack_.pop_back(); LibertyGroup *parent = - liberty_group_stack.empty() ? nullptr : liberty_group_stack.back(); - if (parent && liberty_group_visitor->save(group)) { + group_stack_.empty() ? nullptr : group_stack_.back(); + if (parent && group_visitor_->save(group)) { parent->addSubgroup(group); return group; } @@ -135,6 +153,92 @@ libertyGroupEnd() } } +LibertyGroup * +LibertyParser::group() +{ + return group_stack_.back(); +} + +void +LibertyParser::deleteGroups() +{ + group_stack_.deleteContentsClear(); +} + +LibertyStmt * +LibertyParser::makeSimpleAttr(const char *name, + LibertyAttrValue *value, + int line) +{ + LibertyAttr *attr = new LibertySimpleAttr(name, value, line); + group_visitor_->visitAttr(attr); + LibertyGroup *group = this->group(); + if (group && group_visitor_->save(attr)) { + group->addAttribute(attr); + return attr; + } + else { + delete attr; + return nullptr; + } +} + +LibertyStmt * +LibertyParser::makeComplexAttr(const char *name, + LibertyAttrValueSeq *values, + int line) +{ + // Defines have the same syntax as complex attributes. + // Detect and convert them. + if (stringEq(name, "define")) { + LibertyStmt *define = makeDefine(values, line); + stringDelete(name); + LibertyAttrValueSeq::Iterator attr_iter(values); + while (attr_iter.hasNext()) + delete attr_iter.next(); + delete values; + return define; + } + else { + LibertyAttr *attr = new LibertyComplexAttr(name, values, line); + group_visitor_->visitAttr(attr); + if (group_visitor_->save(attr)) { + LibertyGroup *group = this->group(); + group->addAttribute(attr); + return attr; + } + delete attr; + return nullptr; + } +} + +LibertyStmt * +LibertyParser::makeVariable(char *var, + float value, + int line) +{ + LibertyVariable *variable = new LibertyVariable(var, value, line); + group_visitor_->visitVariable(variable); + if (group_visitor_->save(variable)) + return variable; + else { + delete variable; + return nullptr; + } +} + +LibertyAttrValue * +LibertyParser::makeStringAttrValue(char *value) +{ + return new LibertyStringAttrValue(value); +} + +LibertyAttrValue * +LibertyParser::makeFloatAttrValue(float value) +{ + return new LibertyFloatAttrValue(value); +} + //////////////////////////////////////////////////////////////// LibertyStmt::LibertyStmt(int line) : @@ -274,31 +378,6 @@ LibertyAttr::~LibertyAttr() stringDelete(name_); } -LibertyStmt * -makeLibertySimpleAttr(const char *name, - LibertyAttrValue *value, - int line) -{ - LibertyAttr *attr = new LibertySimpleAttr(name, value, line); - if (liberty_group_visitor) - liberty_group_visitor->visitAttr(attr); - LibertyGroup *group = libertyGroup(); - if (group && liberty_group_visitor->save(attr)) { - group->addAttribute(attr); - return attr; - } - else { - delete attr; - return nullptr; - } -} - -LibertyGroup * -libertyGroup() -{ - return liberty_group_stack.back(); -} - LibertySimpleAttr::LibertySimpleAttr(const char *name, LibertyAttrValue *value, int line) : @@ -319,37 +398,6 @@ LibertySimpleAttr::values() const return nullptr; } -LibertyStmt * -makeLibertyComplexAttr(const char *name, - LibertyAttrValueSeq *values, - int line) -{ - // Defines have the same syntax as complex attributes. - // Detect and convert them. - if (stringEq(name, "define")) { - LibertyStmt *define = makeLibertyDefine(values, line); - stringDelete(name); - LibertyAttrValueSeq::Iterator attr_iter(values); - while (attr_iter.hasNext()) - delete attr_iter.next(); - delete values; - return define; - } - else { - LibertyAttr *attr = new LibertyComplexAttr(name, values, line); - if (liberty_group_visitor) { - liberty_group_visitor->visitAttr(attr); - if (liberty_group_visitor->save(attr)) { - LibertyGroup *group = libertyGroup(); - group->addAttribute(attr); - return attr; - } - } - delete attr; - return nullptr; - } -} - LibertyComplexAttr::LibertyComplexAttr(const char *name, LibertyAttrValueSeq *values, int line) : @@ -375,12 +423,6 @@ LibertyComplexAttr::firstValue() return nullptr; } -LibertyAttrValue * -makeLibertyStringAttrValue(char *value) -{ - return new LibertyStringAttrValue(value); -} - LibertyStringAttrValue::LibertyStringAttrValue(const char *value) : LibertyAttrValue(), value_(value) @@ -405,12 +447,6 @@ LibertyStringAttrValue::stringValue() return value_; } -LibertyAttrValue * -makeLibertyFloatAttrValue(float value) -{ - return new LibertyFloatAttrValue(value); -} - LibertyFloatAttrValue::LibertyFloatAttrValue(float value) : value_(value) { @@ -431,61 +467,6 @@ LibertyFloatAttrValue::stringValue() //////////////////////////////////////////////////////////////// -static LibertyStmt * -makeLibertyDefine(LibertyAttrValueSeq *values, - int line) -{ - LibertyDefine *define = nullptr; - if (values->size() == 3) { - const char *define_name = (*values)[0]->stringValue(); - const char *group_type_name = (*values)[1]->stringValue(); - const char *value_type_name = (*values)[2]->stringValue(); - LibertyAttrType value_type = attrValueType(value_type_name); - LibertyGroupType group_type = groupType(group_type_name); - define = new LibertyDefine(stringCopy(define_name), group_type, - value_type, line); - LibertyGroup *group = libertyGroup(); - group->addDefine(define); - } - else - liberty_report->fileWarn(24, liberty_filename, line, - "define does not have three arguments."); - return define; -} - -// The Liberty User Guide Version 2001.08 fails to define the strings -// used to define valid attribute types. Beyond "string" these are -// guesses. -static LibertyAttrType -attrValueType(const char *value_type_name) -{ - if (stringEq(value_type_name, "string")) - return LibertyAttrType::attr_string; - else if (stringEq(value_type_name, "integer")) - return LibertyAttrType::attr_int; - else if (stringEq(value_type_name, "float")) - return LibertyAttrType::attr_double; - else if (stringEq(value_type_name, "boolean")) - return LibertyAttrType::attr_boolean; - else - return LibertyAttrType::attr_unknown; -} - -static LibertyGroupType -groupType(const char *group_type_name) -{ - if (stringEq(group_type_name, "library")) - return LibertyGroupType::library; - else if (stringEq(group_type_name, "cell")) - return LibertyGroupType::cell; - else if (stringEq(group_type_name, "pin")) - return LibertyGroupType::pin; - else if (stringEq(group_type_name, "timing")) - return LibertyGroupType::timing; - else - return LibertyGroupType::unknown; -} - LibertyDefine::LibertyDefine(const char *name, LibertyGroupType group_type, LibertyAttrType value_type, @@ -504,21 +485,6 @@ LibertyDefine::~LibertyDefine() //////////////////////////////////////////////////////////////// -LibertyStmt * -makeLibertyVariable(char *var, - float value, - int line) -{ - LibertyVariable *variable = new LibertyVariable(var, value, line); - liberty_group_visitor->visitVariable(variable); - if (liberty_group_visitor->save(variable)) - return variable; - else { - delete variable; - return nullptr; - } -} - LibertyVariable::LibertyVariable(const char *var, float value, int line) : @@ -535,82 +501,78 @@ LibertyVariable::~LibertyVariable() //////////////////////////////////////////////////////////////// +LibertyScanner::LibertyScanner(std::istream *stream, + const char *filename, + LibertyParser *reader, + Report *report) : + yyFlexLexer(stream), + stream_(stream), + filename_(filename), + reader_(reader), + report_(report), + stream_prev_(nullptr) +{ +} + bool -libertyInInclude() +LibertyScanner::includeBegin() { - return liberty_filename_prev != nullptr; -} + if (stream_prev_ != nullptr) + error("nested include_file's are not supported"); + else { + // include_file(filename); + std::regex include_regexp("include_file *\\( *([^)]+) *\\) *;?"); + std::cmatch matches; + if (std::regex_match(yytext, matches, include_regexp)) { + string filename = matches[1].str(); + gzstream::igzstream *stream = new gzstream::igzstream(filename.c_str()); + if (stream->is_open()) { + yypush_buffer_state(yy_create_buffer(stream, 256)); -void -libertyIncludeBegin(const char *filename) -{ - gzFile stream = gzopen(filename, "r" ); - if (stream) { - liberty_stream_prev = liberty_stream; - liberty_filename_prev = liberty_filename; - liberty_line_prev = liberty_line; + filename_prev_ = filename_; + stream_prev_ = stream_; - liberty_stream = stream; - liberty_filename = filename; - liberty_line = 1; + filename_ = filename; + reader_->setFilename(filename); + stream_ = stream; + return true; + } + else { + report_->fileWarn(25, filename_.c_str(), yylineno, + "cannot open include file %s.", filename.c_str()); + delete stream; + } + } + else + error("include_file syntax error."); } - else - liberty_report->fileWarn(25, sta::liberty_filename, sta::liberty_line, - "cannot open include file %s.", filename); + return false; } void -libertyIncludeEnd() +LibertyScanner::fileEnd() { - gzclose(liberty_stream); - liberty_stream = liberty_stream_prev; - liberty_filename = liberty_filename_prev; - liberty_line = liberty_line_prev; + if (stream_prev_) + delete stream_; + stream_ = stream_prev_; + filename_ = filename_prev_; + stream_prev_ = nullptr; - liberty_filename_prev = nullptr; - liberty_stream_prev = nullptr; + yypop_buffer_state(); } void -libertyIncrLine() +LibertyScanner::error(const char *msg) { - sta::liberty_line++; -} - -int -libertyLine() -{ - return liberty_line; + report_->fileError(1866, filename_.c_str(), lineno(), "%s", msg); } void -libertyParseError(const char *fmt, ...) +LibertyParse::error(const location_type &loc, + const string &msg) { - va_list args; - va_start(args, fmt); - sta::liberty_report->vfileError(25, sta::liberty_filename, sta::liberty_line, - fmt, args); - va_end(args); -} - -void -deleteLibertyGroups() -{ - liberty_group_stack.deleteContentsClear(); + reader->report()->fileError(164, reader->filename().c_str(), + loc.begin.line, "%s", msg.c_str()); } } // namespace - -//////////////////////////////////////////////////////////////// -// Global namespace - -void libertyParseFlushBuffer(); - -int -LibertyParse_error(const char *msg) -{ - libertyParseFlushBuffer(); - sta::liberty_report->fileError(26, sta::liberty_filename, sta::liberty_line, - "%s.", msg); - return 0; -} diff --git a/liberty/LibertyParser.hh b/liberty/LibertyParser.hh index 8d48c188..4006f37a 100644 --- a/liberty/LibertyParser.hh +++ b/liberty/LibertyParser.hh @@ -43,6 +43,7 @@ class LibertyAttrValue; class LibertyVariable; class LibertySubgroupIterator; class LibertyAttrIterator; +class LibertyScanner; typedef Vector LibertyStmtSeq; typedef Vector LibertyGroupSeq; @@ -53,25 +54,50 @@ typedef Vector LibertyAttrValueSeq; typedef Map LibertyVariableMap; typedef MapLibertyGroupVisitorMap; typedef LibertyAttrValueSeq::Iterator LibertyAttrValueIterator; +typedef Vector LibertyGroupSeq; enum class LibertyAttrType { attr_string, attr_int, attr_double, attr_boolean, attr_unknown }; enum class LibertyGroupType { library, cell, pin, timing, unknown }; -// flex YY_INPUT yy_n_chars arg changed definition from int to size_t, -// so provide both forms. -void -libertyGetChars(char *buf, - size_t &result, - size_t max_size); -void -libertyGetChars(char *buf, - int &result, - size_t max_size); +class LibertyParser +{ +public: + LibertyParser(const char *filename, + LibertyGroupVisitor *library_visitor, + Report *report); + const string &filename() const { return filename_; } + void setFilename(const string &filename); + Report *report() const { return report_; } + LibertyStmt *makeDefine(LibertyAttrValueSeq *values, + int line); + LibertyAttrType attrValueType(const char *value_type_name); + LibertyGroupType groupType(const char *group_type_name); + void groupBegin(const char *type, + LibertyAttrValueSeq *params, + int line); + LibertyGroup *groupEnd(); + LibertyGroup *group(); + void deleteGroups(); + LibertyStmt *makeSimpleAttr(const char *name, + LibertyAttrValue *value, + int line); + LibertyStmt *makeComplexAttr(const char *name, + LibertyAttrValueSeq *values, + int line); + LibertyAttrValue *makeStringAttrValue(char *value); + LibertyAttrValue *makeFloatAttrValue(float value); + LibertyStmt *makeVariable(char *var, + float value, + int line); -#define YY_INPUT(buf,result,max_size) \ - sta::libertyGetChars(buf, result, max_size) +private: + string filename_; + LibertyGroupVisitor *group_visitor_; + Report *report_; + LibertyGroupSeq group_stack_; +}; // Abstract base class for liberty statements. class LibertyStmt @@ -289,52 +315,8 @@ public: virtual bool save(LibertyVariable *variable) = 0; }; -void -libertyIncludeBegin(const char *filename); -void -libertyIncludeEnd(); -bool -libertyInInclude(); -void -libertyIncrLine(); -void -libertyParseError(const char *fmt, - ...); -int -libertyLine(); - void parseLibertyFile(const char *filename, LibertyGroupVisitor *library_visitor, Report *report); -void -libertyGroupBegin(const char *type, - LibertyAttrValueSeq *params, - int line); -LibertyGroup * -libertyGroupEnd(); -LibertyGroup * -libertyGroup(); -LibertyStmt * -makeLibertyComplexAttr(const char *name, - LibertyAttrValueSeq *values, - int line); -LibertyStmt * -makeLibertySimpleAttr(const char *name, - LibertyAttrValue *value, - int line); -LibertyAttrValue * -makeLibertyFloatAttrValue(float value); -LibertyAttrValue * -makeLibertyStringAttrValue(char *value); -LibertyStmt * -makeLibertyVariable(char *var, - float value, - int line); - } // namespace - -// Global namespace. -int -LibertyParse_error(const char *msg); - diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index e05e08a7..4acff872 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -110,6 +110,7 @@ LibertyReader::init(const char *filename, in_bus_ = false; in_bundle_ = false; in_ccsn_ = false; + in_ecsm_waveform_ = false; sequential_ = nullptr; statetable_ = nullptr; timing_ = nullptr; @@ -570,6 +571,9 @@ LibertyReader::defineVisitors() &LibertyReader::endCcsn); defineGroupVisitor("output_ccb", &LibertyReader::beginCcsn, &LibertyReader::endCcsn); + + defineGroupVisitor("ecsm_waveform", &LibertyReader::beginEcsmWaveform, + &LibertyReader::endEcsmWaveform); } void @@ -1520,7 +1524,7 @@ LibertyReader::visitIndex(int index, { if (tbl_template_ // Ignore index_xx in ecsm_waveform groups. - && !stringEq(libertyGroup()->type(), "ecsm_waveform")) { + && !in_ecsm_waveform_) { FloatSeq *axis_values = readFloatSeq(attr, 1.0F); if (axis_values) { if (axis_values->empty()) @@ -4657,7 +4661,7 @@ LibertyReader::visitValues(LibertyAttr *attr) { if (tbl_template_ // Ignore values in ecsm_waveform groups. - && !stringEq(libertyGroup()->type(), "ecsm_waveform")) + && !in_ecsm_waveform_) makeTable(attr, table_model_scale_); } @@ -5667,6 +5671,32 @@ LibertyReader::visitVoltageName(LibertyAttr *attr) } } +// Contents Ignored. +void +LibertyReader::beginCcsn(LibertyGroup *) +{ + in_ccsn_ = true; +} + +void +LibertyReader::endCcsn(LibertyGroup *) +{ + in_ccsn_ = false; +} + +// Contents Ignored. +void +LibertyReader::beginEcsmWaveform(LibertyGroup *) +{ + in_ecsm_waveform_ = true; +} + +void +LibertyReader::endEcsmWaveform(LibertyGroup *) +{ + in_ecsm_waveform_ = false; +} + //////////////////////////////////////////////////////////////// LibertyFunc::LibertyFunc(const char *expr, diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index 69db54c7..7e952f09 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -490,30 +490,10 @@ public: void visitDriverWaveformRiseFall(LibertyAttr *attr, const RiseFall *rf); - // ccsn (not implemented, this is needed to properly ignore ccsn groups) - void beginCcsn(LibertyGroup *) { in_ccsn_ = true; } - void endCcsn(LibertyGroup *) { in_ccsn_ = false; } - - // Visitors for derived classes to overload. - virtual void beginGroup1(LibertyGroup *) {} - virtual void beginGroup2(LibertyGroup *) {} - virtual void beginGroup3(LibertyGroup *) {} - virtual void beginGroup4(LibertyGroup *) {} - virtual void beginGroup5(LibertyGroup *) {} - virtual void endGroup1(LibertyGroup *) {} - virtual void endGroup2(LibertyGroup *) {} - virtual void endGroup3(LibertyGroup *) {} - virtual void endGroup4(LibertyGroup *) {} - virtual void endGroup5(LibertyGroup *) {} - virtual void visitAttr1(LibertyAttr *) {} - virtual void visitAttr2(LibertyAttr *) {} - virtual void visitAttr3(LibertyAttr *) {} - virtual void visitAttr4(LibertyAttr *) {} - virtual void visitAttr5(LibertyAttr *) {} - virtual void visitAttr6(LibertyAttr *) {} - virtual void visitAttr7(LibertyAttr *) {} - virtual void visitAttr8(LibertyAttr *) {} - virtual void visitAttr9(LibertyAttr *) {} + void beginCcsn(LibertyGroup *group); + void endCcsn(LibertyGroup *group); + void beginEcsmWaveform(LibertyGroup *group); + void endEcsmWaveform(LibertyGroup *group); protected: TimingModel *makeScalarCheckModel(float value, @@ -641,6 +621,7 @@ protected: bool in_bus_; bool in_bundle_; bool in_ccsn_; + bool in_ecsm_waveform_; TableAxisVariable axis_var_[3]; FloatSeq *axis_values_[3]; int type_bit_from_; diff --git a/liberty/LibertyScanner.hh b/liberty/LibertyScanner.hh new file mode 100644 index 00000000..4e35c0cd --- /dev/null +++ b/liberty/LibertyScanner.hh @@ -0,0 +1,74 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#pragma once + +#ifndef __FLEX_LEXER_H +#undef yyFlexLexer +#define yyFlexLexer LibertyFlexLexer +#include +#endif + +#include "location.hh" +#include "LibertyParse.hh" + +namespace sta { + +class Report; +class LibertyParser; + +class LibertyScanner : public LibertyFlexLexer +{ +public: + LibertyScanner(std::istream *stream, + const char *filename, + LibertyParser *reader, + Report *report); + virtual ~LibertyScanner() {} + + virtual int lex(LibertyParse::semantic_type *const yylval, + LibertyParse::location_type *yylloc); + // YY_DECL defined in LibertyLex.ll + // Method body created by flex in LibertyLex.cc + + // Get rid of override virtual function warning. + using FlexLexer::yylex; + +private: + bool includeBegin(); + void fileEnd(); + void error(const char *msg); + + std::istream *stream_; + string filename_; + LibertyParser *reader_; + Report *report_; + string token_; + + // Previous lex state for include files. + string filename_prev_; + std::istream *stream_prev_; +}; + +} // namespace diff --git a/sdf/SdfParse.yy b/sdf/SdfParse.yy index 11ef84a3..1730daf7 100644 --- a/sdf/SdfParse.yy +++ b/sdf/SdfParse.yy @@ -33,8 +33,6 @@ // warning: variable 'yynerrs_' set but not used #pragma GCC diagnostic ignored "-Wunused-but-set-variable" - -#define loc_line(loc) loc.begin.line %} %require "3.0" diff --git a/sdf/SdfReader.cc b/sdf/SdfReader.cc index 768f093e..9d561613 100644 --- a/sdf/SdfReader.cc +++ b/sdf/SdfReader.cc @@ -139,8 +139,8 @@ SdfReader::~SdfReader() bool SdfReader::read() { - gzstream::igzstream stream(filename_); - if (stream.good()) { + gzstream::igzstream stream(filename_.c_str()); + if (stream.is_open()) { Stats stats(debug_, report_); SdfScanner scanner(&stream, filename_, this, report_); scanner_ = &scanner; @@ -150,7 +150,7 @@ SdfReader::read() return success; } else - throw FileNotReadable(filename_); + throw FileNotReadable(filename_.c_str()); } void @@ -994,7 +994,7 @@ SdfReader::sdfWarn(int id, { va_list args; va_start(args, fmt); - report_->vfileWarn(id, filename_, scanner_->lineno(), fmt, args); + report_->vfileWarn(id, filename_.c_str(), scanner_->lineno(), fmt, args); va_end(args); } @@ -1004,7 +1004,7 @@ SdfReader::sdfError(int id, { va_list args; va_start(args, fmt); - report_->vfileError(id, filename_, scanner_->lineno(), fmt, args); + report_->vfileError(id, filename_.c_str(), scanner_->lineno(), fmt, args); va_end(args); } @@ -1087,7 +1087,7 @@ SdfTriple::hasValue() const //////////////////////////////////////////////////////////////// SdfScanner::SdfScanner(std::istream *stream, - const char *filename, + const string &filename, SdfReader *reader, Report *report) : yyFlexLexer(stream), @@ -1100,7 +1100,7 @@ SdfScanner::SdfScanner(std::istream *stream, void SdfScanner::error(const char *msg) { - report_->fileError(1866, filename_, lineno(), "%s", msg); + report_->fileError(1866, filename_.c_str(), lineno(), "%s", msg); } //////////////////////////////////////////////////////////////// @@ -1109,7 +1109,8 @@ void SdfParse::error(const location_type &loc, const string &msg) { - reader->report()->fileError(164,reader->filename(),loc.begin.line,"%s",msg.c_str()); + reader->report()->fileError(164,reader->filename().c_str(), + loc.begin.line,"%s",msg.c_str()); } } // namespace diff --git a/sdf/SdfReaderPvt.hh b/sdf/SdfReaderPvt.hh index b70b80e8..64b00eaf 100644 --- a/sdf/SdfReaderPvt.hh +++ b/sdf/SdfReaderPvt.hh @@ -146,7 +146,7 @@ public: void setInIncremental(bool incr); string *makeBusName(string *bus_name, int index); - const char *filename() { return filename_; } + const string &filename() const { return filename_; } void sdfWarn(int id, const char *fmt, ...); void sdfError(int id, @@ -190,7 +190,7 @@ private: Port *findPort(const Cell *cell, const string *port_name); - const char *filename_; + string filename_; SdfScanner *scanner_; const char *path_; // Which values to pull out of the sdf triples. diff --git a/sdf/SdfScanner.hh b/sdf/SdfScanner.hh index a4e117f0..ef74ccd3 100644 --- a/sdf/SdfScanner.hh +++ b/sdf/SdfScanner.hh @@ -41,7 +41,7 @@ class SdfScanner : public SdfFlexLexer { public: SdfScanner(std::istream *stream, - const char *filename, + const string &filename, SdfReader *reader, Report *report); virtual ~SdfScanner() {} @@ -57,10 +57,10 @@ public: using FlexLexer::yylex; private: - string token_; - const char *filename_; + string filename_; SdfReader *reader_; Report *report_; + string token_; }; } // namespace diff --git a/util/gzstream.hh b/util/gzstream.hh index a6e7803e..ec2ded6c 100644 --- a/util/gzstream.hh +++ b/util/gzstream.hh @@ -193,7 +193,8 @@ public: igzstream() : std::istream( &buf) {} igzstream( const char* name, int open_mode = std::ios::in) : gzstreambase( name, open_mode), std::istream( &buf) {} - gzstreambuf* rdbuf() { return gzstreambase::rdbuf(); } + int is_open() { return buf.is_open(); } + gzstreambuf* rdbuf() { return gzstreambase::rdbuf(); } void open( const char* name, int open_mode = std::ios::in) { gzstreambase::open( name, open_mode); } diff --git a/verilog/VerilogReader.cc b/verilog/VerilogReader.cc index 664a0d38..3ddc9b22 100644 --- a/verilog/VerilogReader.cc +++ b/verilog/VerilogReader.cc @@ -168,7 +168,7 @@ bool VerilogReader::read(const char *filename) { gzstream::igzstream stream(filename); - if (stream.good()) { + if (stream.is_open()) { Stats stats(debug_, report_); VerilogScanner scanner(&stream, filename, report_); VerilogParse parser(&scanner, this);