// 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. #include "LibertyParser.hh" #include #include #include #include "Zlib.hh" #include "Report.hh" #include "Error.hh" #include "StringUtil.hh" #include "LibertyScanner.hh" namespace sta { using std::string; void parseLibertyFile(const char *filename, LibertyGroupVisitor *library_visitor, Report *report) { gzstream::igzstream stream(filename); if (stream.is_open()) { LibertyParser reader(filename, library_visitor, report); LibertyScanner scanner(&stream, filename, &reader, report); LibertyParse parser(&scanner, &reader); parser.parse(); } else 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(define_name, group_type, value_type, line); LibertyGroup *group = this->group(); group->addDefine(define); } else report_->fileWarn(24, filename_.c_str(), 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. LibertyAttrType LibertyParser::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; } LibertyGroupType LibertyParser::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; } void LibertyParser::groupBegin(const char *type, LibertyAttrValueSeq *params, int line) { LibertyGroup *group = new LibertyGroup(type, params, line); stringDelete(type); group_visitor_->begin(group); group_stack_.push_back(group); } LibertyGroup * LibertyParser::groupEnd() { LibertyGroup *group = this->group(); group_visitor_->end(group); group_stack_.pop_back(); LibertyGroup *parent = group_stack_.empty() ? nullptr : group_stack_.back(); if (parent && group_visitor_->save(group)) { parent->addSubgroup(group); return group; } else { delete group; return nullptr; } } 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); stringDelete(name); 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); stringDelete(name); 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(const char *var, float value, int line) { LibertyVariable *variable = new LibertyVariable(var, value, line); stringDelete(var); group_visitor_->visitVariable(variable); if (group_visitor_->save(variable)) return variable; else { delete variable; return nullptr; } } LibertyAttrValue * LibertyParser::makeStringAttrValue(char *value) { LibertyAttrValue *attr = new LibertyStringAttrValue(value); stringDelete(value); return attr; } LibertyAttrValue * LibertyParser::makeFloatAttrValue(float value) { return new LibertyFloatAttrValue(value); } //////////////////////////////////////////////////////////////// LibertyStmt::LibertyStmt(int line) : line_(line) { } LibertyGroup::LibertyGroup(const char *type, LibertyAttrValueSeq *params, int line) : LibertyStmt(line), type_(type), params_(params), attrs_(nullptr), attr_map_(nullptr), subgroups_(nullptr), define_map_(nullptr) { } void LibertyGroup::addSubgroup(LibertyGroup *subgroup) { if (subgroups_ == nullptr) subgroups_ = new LibertyGroupSeq; subgroups_->push_back(subgroup); } void LibertyGroup::addDefine(LibertyDefine *define) { if (define_map_ == nullptr) define_map_ = new LibertyDefineMap; const char *define_name = define->name(); LibertyDefine *prev_define = define_map_->findKey(define_name); if (prev_define) { define_map_->erase(define_name); delete prev_define; } (*define_map_)[define_name] = define; } void LibertyGroup::addAttribute(LibertyAttr *attr) { if (attrs_ == nullptr) attrs_ = new LibertyAttrSeq; attrs_->push_back(attr); if (attr_map_) (*attr_map_)[attr->name()] = attr; } LibertyGroup::~LibertyGroup() { if (params_) { params_->deleteContents(); delete params_; } if (attrs_) { LibertyAttrSeq::Iterator iter(attrs_); attrs_->deleteContents(); delete attrs_; delete attr_map_; } if (subgroups_) { subgroups_->deleteContents(); delete subgroups_; } if (define_map_) { define_map_->deleteContents(); delete define_map_; } } const char * LibertyGroup::firstName() { if (params_ && params_->size() > 0) { LibertyAttrValue *value = (*params_)[0]; if (value->isString()) return value->stringValue(); } return nullptr; } const char * LibertyGroup::secondName() { if (params_ && params_->size() > 1) { LibertyAttrValue *value = (*params_)[1]; if (value->isString()) return value->stringValue(); } return nullptr; } LibertyAttr * LibertyGroup::findAttr(const char *name) { if (attrs_) { if (attr_map_ == nullptr) { // Build attribute name map on demand. LibertyAttrSeq::Iterator attr_iter(attrs_); while (attr_iter.hasNext()) { LibertyAttr *attr = attr_iter.next(); (*attr_map_)[attr->name()] = attr; } } return attr_map_->findKey(name); } else return nullptr; } LibertySubgroupIterator::LibertySubgroupIterator(LibertyGroup *group) : LibertyGroupSeq::Iterator(group->subgroups()) { } LibertyAttrIterator::LibertyAttrIterator(LibertyGroup *group) : LibertyAttrSeq::Iterator(group->attrs()) { } //////////////////////////////////////////////////////////////// LibertyAttr::LibertyAttr(const char *name, int line) : LibertyStmt(line), name_(name) { } LibertySimpleAttr::LibertySimpleAttr(const char *name, LibertyAttrValue *value, int line) : LibertyAttr(name, line), value_(value) { } LibertySimpleAttr::~LibertySimpleAttr() { delete value_; } LibertyAttrValueSeq * LibertySimpleAttr::values() const { criticalError(1125, "valueIterator called for LibertySimpleAttribute"); return nullptr; } LibertyComplexAttr::LibertyComplexAttr(const char *name, LibertyAttrValueSeq *values, int line) : LibertyAttr(name, line), values_(values) { } LibertyComplexAttr::~LibertyComplexAttr() { if (values_) { values_->deleteContents(); delete values_; } } LibertyAttrValue * LibertyComplexAttr::firstValue() { if (values_ && values_->size() > 0) return (*values_)[0]; else return nullptr; } LibertyStringAttrValue::LibertyStringAttrValue(const char *value) : LibertyAttrValue(), value_(value) { } float LibertyStringAttrValue::floatValue() { criticalError(1126, "LibertyStringAttrValue called for float value"); return 0.0; } const char * LibertyStringAttrValue::stringValue() { return value_.c_str(); } LibertyFloatAttrValue::LibertyFloatAttrValue(float value) : value_(value) { } float LibertyFloatAttrValue::floatValue() { return value_; } const char * LibertyFloatAttrValue::stringValue() { criticalError(1127, "LibertyStringAttrValue called for float value"); return nullptr; } //////////////////////////////////////////////////////////////// LibertyDefine::LibertyDefine(const char *name, LibertyGroupType group_type, LibertyAttrType value_type, int line) : LibertyStmt(line), name_(name), group_type_(group_type), value_type_(value_type) { } //////////////////////////////////////////////////////////////// LibertyVariable::LibertyVariable(const char *var, float value, int line) : LibertyStmt(line), var_(var), value_(value) { } //////////////////////////////////////////////////////////////// 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 LibertyScanner::includeBegin() { 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)); filename_prev_ = filename_; stream_prev_ = stream_; 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."); } return false; } void LibertyScanner::fileEnd() { if (stream_prev_) delete stream_; stream_ = stream_prev_; filename_ = filename_prev_; stream_prev_ = nullptr; yypop_buffer_state(); } void LibertyScanner::error(const char *msg) { report_->fileError(1866, filename_.c_str(), lineno(), "%s", msg); } } // namespace