liberty parser c++

commit 1abf72bc3430d34a51d82992f1c753f0274a662a
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Jan 27 08:01:04 2025 -0700

    rm unused lib visitors

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 1e76acfc7829a8ba82f96d369fae6225a7361844
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Jan 26 21:15:46 2025 -0700

    verilog/sdf stream->is_open

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit c4a57c0354ffb6c4edfc3269d56a937c11ad9609
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Jan 26 19:54:41 2025 -0700

    leak

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit b992ed1124a862cb04f0c7617a4575f916c3fe01
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Jan 26 16:39:16 2025 -0700

    liberty mv string_buf to scanner

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 894cbfa5d5b731738dcc60d492689fad9d13bd40
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Jan 26 16:29:42 2025 -0700

    liberty use regex to parse include file

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 176225849d3fcac0b2be1a5b623270c386daed3d
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Jan 26 15:48:09 2025 -0700

    liberty include filename

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 516e12721d7185015d8c29e8b16fa185f0f46983
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Jan 26 15:31:18 2025 -0700

    liberty include

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 32098a2159798dfbb80140927949bb36f480093d
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Jan 26 15:01:47 2025 -0700

    liberty include

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 880214e632d756c3199b000fee88fd4fdffac371
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Jan 26 13:55:02 2025 -0700

    liberty include

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit ad1efca842a6d7ee608ffd5a19a69885786b77fa
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Jan 26 10:11:07 2025 -0700

    liberty passes all but include

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit e71cf1f39dd09e81cf2b0e5a12dcf51675f2a6fd
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Jan 26 10:01:08 2025 -0700

    liberty parser use class compiles

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 02dea0ff753b0fa12f280661a46e2c0ef2432357
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sat Jan 25 19:08:06 2025 -0700

    liberty parser compiles

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2025-01-27 08:33:35 -07:00
parent c9a8726707
commit fb6e7f9fa7
14 changed files with 495 additions and 497 deletions

View File

@ -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_

View File

@ -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<float>(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. */
<comment>[^*\r\n]* /* eat anything that's not a '*' */
<comment>"*"+[^*/\r\n]* /* eat up '*'s not followed by '/'s */
<comment>{EOL} sta::libertyIncrLine();
<comment>{EOL} { loc->lines(); loc->step(); }
<comment>"*"+"/" BEGIN(INITIAL);
\" {
string_buf.erase();
token_.clear();
BEGIN(qstring);
}
<qstring>\" {
BEGIN(INITIAL);
LibertyParse_lval.string = sta::stringCopy(string_buf.c_str());
return STRING;
yylval->string = stringCopy(token_.c_str());
return token::STRING;
}
<qstring>{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;
}
<qstring>\\{EOL} {
/* Line continuation. */
sta::libertyIncrLine();
loc->lines(); loc->step();
}
<qstring>\\. {
/* Escaped character. */
string_buf += '\\';
string_buf += LibertyLex_text[1];
token_ += '\\';
token_ += yytext[1];
}
<qstring>[^\\\r\n\"]+ {
/* Anything but escape, return or double quote */
string_buf += LibertyLex_text;
token_ += yytext;
}
<qstring><<EOF>> {
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]; }
<<EOF>> {
#ifdef INCLUDE_SUPPORTED
if (sta::libertyInInclude()) {
sta::libertyIncludeEnd();
yypop_buffer_state();
}
else
#endif
yyterminate();
}
<<EOF>> { if (stream_prev_)
fileEnd();
else
yyterminate();
}
%%

View File

@ -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 <cstdlib>
#include <cstring>
#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> attr_values
%type <attr_value> attr_value
%type <string> string expr expr_term expr_term1 volt_expr
%type <line> line
%type <ch> 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. */

View File

@ -26,106 +26,124 @@
#include <cstdio>
#include <cstring>
#include <regex>
#include "Zlib.hh"
#include "Report.hh"
#include "Error.hh"
#include "StringUtil.hh"
// Global namespace
int
LibertyParse_parse();
#include "LibertyScanner.hh"
namespace sta {
typedef Vector<LibertyGroup*> 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;
}

View File

@ -43,6 +43,7 @@ class LibertyAttrValue;
class LibertyVariable;
class LibertySubgroupIterator;
class LibertyAttrIterator;
class LibertyScanner;
typedef Vector<LibertyStmt*> LibertyStmtSeq;
typedef Vector<LibertyGroup*> LibertyGroupSeq;
@ -53,25 +54,50 @@ typedef Vector<LibertyAttrValue*> LibertyAttrValueSeq;
typedef Map<const char *, float, CharPtrLess> LibertyVariableMap;
typedef Map<const char*,LibertyGroupVisitor*,CharPtrLess>LibertyGroupVisitorMap;
typedef LibertyAttrValueSeq::Iterator LibertyAttrValueIterator;
typedef Vector<LibertyGroup*> 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);

View File

@ -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,

View File

@ -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_;

74
liberty/LibertyScanner.hh Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
//
// 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 <FlexLexer.h>
#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

View File

@ -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"

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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);
}

View File

@ -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);