// 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
#include "Report.hh"
#include "liberty/LibertyParser.hh"
#include "liberty/LibertyScanner.hh"
#undef yylex
#define yylex scanner->lex
// warning: variable 'yynerrs_' set but not used
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#define loc_line(loc) loc.begin.line
void
sta::LibertyParse::error(const location_type &loc,
const std::string &msg)
{
reader->report()->fileError(164, reader->filename().c_str(),
loc.begin.line, "%s", msg.c_str());
}
%}
%require "3.2"
%skeleton "lalr1.cc"
%debug
%define api.namespace {sta}
%locations
%define api.location.file "LibertyLocation.hh"
%define parse.assert
%parse-param { LibertyScanner *scanner }
%parse-param { LibertyParser *reader }
%define api.parser.class {LibertyParse}
%expect 2
%union {
char *string;
float number;
char ch;
sta::LibertyAttrValue *attr_value;
sta::LibertyAttrValueSeq *attr_values;
sta::LibertyGroup *group;
sta::LibertyStmt *stmt;
}
%left '+' '-' '|'
%left '*' '/' '&'
%left '^'
%left '!'
%token FLOAT
%token STRING KEYWORD
%type statement complex_attr simple_attr variable group file
%type attr_values
%type attr_value
%type string expr expr_term expr_term1 volt_expr
%type expr_op volt_op
%start file
%%
file:
group
;
group:
KEYWORD '(' ')' '{'
{ reader->groupBegin($1, nullptr, loc_line(@1)); }
'}' semi_opt
{ $$ = reader->groupEnd(); }
| KEYWORD '(' ')' '{'
{ reader->groupBegin($1, nullptr, loc_line(@1)); }
statements '}' semi_opt
{ $$ = reader->groupEnd(); }
| KEYWORD '(' attr_values ')' '{'
{ reader->groupBegin($1, $3, loc_line(@1)); }
'}' semi_opt
{ $$ = reader->groupEnd(); }
| KEYWORD '(' attr_values ')' '{'
{ reader->groupBegin($1, $3, loc_line(@1)); }
statements '}' semi_opt
{ $$ = reader->groupEnd(); }
;
statements:
statement
| statements statement
;
statement:
simple_attr
| complex_attr
| group
| variable
;
simple_attr:
KEYWORD ':' attr_value semi_opt
{ $$ = reader->makeSimpleAttr($1, $3, loc_line(@1)); }
;
complex_attr:
KEYWORD '(' ')' semi_opt
{ $$ = reader->makeComplexAttr($1, nullptr, loc_line(@1)); }
| KEYWORD '(' attr_values ')' semi_opt
{ $$ = reader->makeComplexAttr($1, $3, loc_line(@1)); }
;
attr_values:
attr_value
{ $$ = new sta::LibertyAttrValueSeq;
$$->push_back($1);
}
| attr_values ',' attr_value
{ $1->push_back($3);
$$ = $1;
}
| attr_values attr_value
{ $1->push_back($2);
$$ = $1;
}
;
variable:
string '=' FLOAT semi_opt
{ $$ = reader->makeVariable($1, $3, loc_line(@1)); }
;
string:
STRING
{ $$ = $1; }
| KEYWORD
{ $$ = $1; }
;
attr_value:
FLOAT
{ $$ = reader->makeFloatAttrValue($1); }
| expr
{ $$ = reader->makeStringAttrValue($1); }
| volt_expr
{ $$ = reader->makeStringAttrValue($1); }
;
/* Voltage expressions are ignored. */
/* Crafted to avoid conflicts with expr */
volt_expr:
FLOAT volt_op FLOAT
{ $$ = sta::stringPrint("%e%c%e", $1, $2, $3); }
| string volt_op FLOAT
{ $$ = sta::stringPrint("%s%c%e", $1, $2, $3);
sta::stringDelete($1);
}
| FLOAT volt_op string
{ $$ = sta::stringPrint("%e%c%s", $1, $2, $3);
sta::stringDelete($3);
}
| volt_expr volt_op FLOAT
{ $$ = sta::stringPrint("%s%c%e", $1, $2, $3);
sta::stringDelete($1);
}
;
volt_op:
'+'
{ $$ = '+'; }
| '-'
{ $$ = '-'; }
| '*'
{ $$ = '*'; }
| '/'
{ $$ = '/'; }
;
expr:
expr_term1
| expr_term1 expr_op expr
{ $$ = sta::stringPrint("%s%c%s", $1, $2, $3);
sta::stringDelete($1);
sta::stringDelete($3);
}
;
expr_term:
string
| '0'
{ $$ = sta::stringPrint("0"); }
| '1'
{ $$ = sta::stringPrint("1"); }
| '(' expr ')'
{ $$ = sta::stringPrint("(%s)", $2);
sta::stringDelete($2);
}
;
expr_term1:
expr_term
| '!' expr_term
{ $$ = sta::stringPrint("!%s", $2);
sta::stringDelete($2);
}
| expr_term '\''
{ $$ = sta::stringPrint("%s'", $1);
sta::stringDelete($1);
}
;
expr_op:
'+'
{ $$ = '+'; }
| '|'
{ $$ = '|'; }
| '*'
{ $$ = '*'; }
| '&'
{ $$ = '&'; }
| '^'
{ $$ = '^'; }
;
semi_opt:
/* empty */
| semi_opt ';'
;
%%