2018-09-28 17:54:21 +02:00
|
|
|
// OpenSTA, Static Timing Analyzer
|
2019-01-01 21:26:11 +01:00
|
|
|
// Copyright (c) 2019, Parallax Software, Inc.
|
2018-09-28 17:54:21 +02:00
|
|
|
//
|
|
|
|
|
// 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/>.
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include "Machine.hh"
|
|
|
|
|
#include "Report.hh"
|
|
|
|
|
#include "Error.hh"
|
|
|
|
|
#include "StringUtil.hh"
|
|
|
|
|
#include "LibertyParser.hh"
|
|
|
|
|
|
|
|
|
|
// Global namespace
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
LibertyParse_parse();
|
|
|
|
|
extern FILE *LibertyLex_in;
|
|
|
|
|
|
|
|
|
|
namespace sta {
|
|
|
|
|
|
|
|
|
|
typedef Vector<LibertyGroup*> LibertyGroupSeq;
|
|
|
|
|
|
|
|
|
|
static const char *liberty_filename;
|
|
|
|
|
static int liberty_line;
|
|
|
|
|
// Previous lex reader state for include files.
|
|
|
|
|
static const char *liberty_filename_prev;
|
|
|
|
|
static int liberty_line_prev;
|
|
|
|
|
static FILE *liberty_stream_prev;
|
|
|
|
|
|
|
|
|
|
static LibertyGroupVisitor *liberty_group_visitor;
|
|
|
|
|
static LibertyGroupSeq liberty_group_stack;
|
|
|
|
|
static Report *liberty_report;
|
|
|
|
|
|
|
|
|
|
static LibertyStmt *
|
|
|
|
|
makeLibertyDefine(LibertyAttrValueSeq *values,
|
|
|
|
|
int line);
|
2019-03-13 01:25:53 +01:00
|
|
|
static LibertyAttrType
|
2018-09-28 17:54:21 +02:00
|
|
|
attrValueType(const char *value_type_name);
|
|
|
|
|
static LibertyGroupType
|
|
|
|
|
groupType(const char *group_type_name);
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
parseLibertyFile(const char *filename,
|
|
|
|
|
LibertyGroupVisitor *library_visitor,
|
|
|
|
|
Report *report)
|
|
|
|
|
{
|
|
|
|
|
LibertyLex_in = fopen(filename, "r");
|
|
|
|
|
if (LibertyLex_in) {
|
|
|
|
|
liberty_group_visitor = library_visitor;
|
|
|
|
|
liberty_group_stack.clear();
|
|
|
|
|
liberty_filename = filename;
|
2019-03-13 01:25:53 +01:00
|
|
|
liberty_filename_prev = nullptr;
|
|
|
|
|
liberty_stream_prev = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
liberty_line = 1;
|
|
|
|
|
liberty_report = report;
|
|
|
|
|
LibertyParse_parse();
|
|
|
|
|
fclose(LibertyLex_in);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw FileNotReadable(filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
libertyGroupBegin(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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyGroup *
|
|
|
|
|
libertyGroupEnd()
|
|
|
|
|
{
|
|
|
|
|
LibertyGroup *group = libertyGroup();
|
|
|
|
|
liberty_group_visitor->end(group);
|
|
|
|
|
liberty_group_stack.pop_back();
|
|
|
|
|
LibertyGroup *parent =
|
2019-03-13 01:25:53 +01:00
|
|
|
liberty_group_stack.empty() ? nullptr : liberty_group_stack.back();
|
2018-09-28 17:54:21 +02:00
|
|
|
if (parent && liberty_group_visitor->save(group)) {
|
|
|
|
|
parent->addSubgroup(group);
|
|
|
|
|
return group;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
delete group;
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
LibertyStmt::LibertyStmt(int line) :
|
|
|
|
|
line_(line)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyGroup::LibertyGroup(const char *type,
|
|
|
|
|
LibertyAttrValueSeq *params,
|
|
|
|
|
int line) :
|
|
|
|
|
LibertyStmt(line),
|
|
|
|
|
type_(type),
|
|
|
|
|
params_(params),
|
2019-03-13 01:25:53 +01:00
|
|
|
attrs_(nullptr),
|
|
|
|
|
attr_map_(nullptr),
|
|
|
|
|
subgroups_(nullptr),
|
|
|
|
|
define_map_(nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
LibertyGroup::addSubgroup(LibertyGroup *subgroup)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
if (subgroups_ == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
subgroups_ = new LibertyGroupSeq;
|
|
|
|
|
subgroups_->push_back(subgroup);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
LibertyGroup::addDefine(LibertyDefine *define)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
if (define_map_ == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
define_map_ = new LibertyDefineMap;
|
|
|
|
|
const char *define_name = define->name();
|
|
|
|
|
LibertyDefine *prev_define = define_map_->findKey(define_name);
|
|
|
|
|
if (prev_define) {
|
|
|
|
|
define_map_->eraseKey(define_name);
|
|
|
|
|
delete prev_define;
|
|
|
|
|
}
|
|
|
|
|
(*define_map_)[define_name] = define;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
LibertyGroup::addAttribute(LibertyAttr *attr)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
if (attrs_ == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
attrs_ = new LibertyAttrSeq;
|
|
|
|
|
attrs_->push_back(attr);
|
|
|
|
|
if (attr_map_)
|
|
|
|
|
(*attr_map_)[attr->name()] = attr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyGroup::~LibertyGroup()
|
|
|
|
|
{
|
|
|
|
|
stringDelete(type_);
|
|
|
|
|
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();
|
|
|
|
|
}
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
LibertyGroup::secondName()
|
|
|
|
|
{
|
|
|
|
|
if (params_ && params_->size() > 1) {
|
|
|
|
|
LibertyAttrValue *value = (*params_)[1];
|
|
|
|
|
if (value->isString())
|
|
|
|
|
return value->stringValue();
|
|
|
|
|
}
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyAttr *
|
|
|
|
|
LibertyGroup::findAttr(const char *name)
|
|
|
|
|
{
|
|
|
|
|
if (attrs_) {
|
2019-03-13 01:25:53 +01:00
|
|
|
if (attr_map_ == nullptr) {
|
2018-09-28 17:54:21 +02:00
|
|
|
// 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
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyGroup *
|
|
|
|
|
libertyGroup()
|
|
|
|
|
{
|
|
|
|
|
return liberty_group_stack.back();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertySimpleAttr::LibertySimpleAttr(const char *name,
|
|
|
|
|
LibertyAttrValue *value,
|
|
|
|
|
int line) :
|
|
|
|
|
LibertyAttr(name, line),
|
|
|
|
|
value_(value)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertySimpleAttr::~LibertySimpleAttr()
|
|
|
|
|
{
|
|
|
|
|
delete value_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyAttrValueSeq *
|
|
|
|
|
LibertySimpleAttr::values() const
|
|
|
|
|
{
|
|
|
|
|
internalError("valueIterator called for LibertySimpleAttribute");
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
delete attr;
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyAttrValue *
|
|
|
|
|
makeLibertyStringAttrValue(char *value)
|
|
|
|
|
{
|
|
|
|
|
return new LibertyStringAttrValue(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyStringAttrValue::LibertyStringAttrValue(const char *value) :
|
|
|
|
|
LibertyAttrValue(),
|
|
|
|
|
value_(value)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyStringAttrValue::~LibertyStringAttrValue()
|
|
|
|
|
{
|
|
|
|
|
stringDelete(value_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
|
|
|
|
LibertyStringAttrValue::floatValue()
|
|
|
|
|
{
|
|
|
|
|
internalError("LibertyStringAttrValue called for float value");
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
LibertyStringAttrValue::stringValue()
|
|
|
|
|
{
|
|
|
|
|
return value_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyAttrValue *
|
|
|
|
|
makeLibertyFloatAttrValue(float value)
|
|
|
|
|
{
|
|
|
|
|
return new LibertyFloatAttrValue(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyFloatAttrValue::LibertyFloatAttrValue(float value) :
|
|
|
|
|
value_(value)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
|
|
|
|
LibertyFloatAttrValue::floatValue()
|
|
|
|
|
{
|
|
|
|
|
return value_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
LibertyFloatAttrValue::stringValue()
|
|
|
|
|
{
|
|
|
|
|
internalError("LibertyStringAttrValue called for float value");
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
static LibertyStmt *
|
|
|
|
|
makeLibertyDefine(LibertyAttrValueSeq *values,
|
|
|
|
|
int line)
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
LibertyDefine *define = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
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();
|
2019-03-13 01:25:53 +01:00
|
|
|
LibertyAttrType value_type = attrValueType(value_type_name);
|
2018-09-28 17:54:21 +02:00
|
|
|
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(liberty_filename, line,
|
|
|
|
|
"define does not have three arguments.\n");
|
|
|
|
|
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.
|
2019-03-13 01:25:53 +01:00
|
|
|
static LibertyAttrType
|
2018-09-28 17:54:21 +02:00
|
|
|
attrValueType(const char *value_type_name)
|
|
|
|
|
{
|
|
|
|
|
if (stringEq(value_type_name, "string"))
|
2019-03-13 01:25:53 +01:00
|
|
|
return LibertyAttrType::attr_string;
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (stringEq(value_type_name, "integer"))
|
2019-03-13 01:25:53 +01:00
|
|
|
return LibertyAttrType::attr_int;
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (stringEq(value_type_name, "float"))
|
2019-03-13 01:25:53 +01:00
|
|
|
return LibertyAttrType::attr_double;
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (stringEq(value_type_name, "boolean"))
|
2019-03-13 01:25:53 +01:00
|
|
|
return LibertyAttrType::attr_boolean;
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2019-03-13 01:25:53 +01:00
|
|
|
return LibertyAttrType::attr_unknown;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static LibertyGroupType
|
|
|
|
|
groupType(const char *group_type_name)
|
|
|
|
|
{
|
|
|
|
|
if (stringEq(group_type_name, "library"))
|
2019-03-13 01:25:53 +01:00
|
|
|
return LibertyGroupType::library;
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (stringEq(group_type_name, "cell"))
|
2019-03-13 01:25:53 +01:00
|
|
|
return LibertyGroupType::cell;
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (stringEq(group_type_name, "pin"))
|
2019-03-13 01:25:53 +01:00
|
|
|
return LibertyGroupType::pin;
|
2018-09-28 17:54:21 +02:00
|
|
|
else if (stringEq(group_type_name, "timing"))
|
2019-03-13 01:25:53 +01:00
|
|
|
return LibertyGroupType::timing;
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2019-03-13 01:25:53 +01:00
|
|
|
return LibertyGroupType::unknown;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyDefine::LibertyDefine(const char *name,
|
|
|
|
|
LibertyGroupType group_type,
|
2019-03-13 01:25:53 +01:00
|
|
|
LibertyAttrType value_type,
|
2018-09-28 17:54:21 +02:00
|
|
|
int line) :
|
|
|
|
|
LibertyStmt(line),
|
|
|
|
|
name_(name),
|
|
|
|
|
group_type_(group_type),
|
|
|
|
|
value_type_(value_type)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyDefine::~LibertyDefine()
|
|
|
|
|
{
|
|
|
|
|
stringDelete(name_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
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;
|
2019-03-13 01:25:53 +01:00
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyVariable::LibertyVariable(const char *var,
|
|
|
|
|
float value,
|
|
|
|
|
int line) :
|
|
|
|
|
LibertyStmt(line),
|
|
|
|
|
var_(var),
|
|
|
|
|
value_(value)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibertyVariable::~LibertyVariable()
|
|
|
|
|
{
|
|
|
|
|
stringDelete(var_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
libertyInInclude()
|
|
|
|
|
{
|
2019-03-13 01:25:53 +01:00
|
|
|
return liberty_filename_prev != nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FILE *
|
|
|
|
|
libertyIncludeBegin(const char *filename)
|
|
|
|
|
{
|
|
|
|
|
FILE *stream = fopen(filename, "r" );
|
2019-03-13 01:25:53 +01:00
|
|
|
if (stream == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
libertyParseError("cannot open include file %s.\n", filename);
|
|
|
|
|
else {
|
|
|
|
|
liberty_filename_prev = liberty_filename;
|
|
|
|
|
liberty_line_prev = liberty_line;
|
|
|
|
|
liberty_stream_prev = LibertyLex_in;
|
|
|
|
|
|
|
|
|
|
liberty_filename = filename;
|
|
|
|
|
liberty_line = 1;
|
|
|
|
|
}
|
|
|
|
|
return stream;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
libertyIncludeEnd()
|
|
|
|
|
{
|
|
|
|
|
fclose(LibertyLex_in);
|
|
|
|
|
liberty_filename = liberty_filename_prev;
|
|
|
|
|
liberty_line = liberty_line_prev;
|
|
|
|
|
LibertyLex_in = liberty_stream_prev;
|
2019-03-13 01:25:53 +01:00
|
|
|
liberty_filename_prev = nullptr;
|
|
|
|
|
liberty_stream_prev = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
libertyIncrLine()
|
|
|
|
|
{
|
|
|
|
|
sta::liberty_line++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
libertyLine()
|
|
|
|
|
{
|
|
|
|
|
return liberty_line;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
libertyParseError(const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
|
sta::liberty_report->vfileError(sta::liberty_filename, sta::liberty_line,
|
|
|
|
|
fmt, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
// Global namespace
|
|
|
|
|
|
|
|
|
|
void libertyParseFlushBuffer();
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
LibertyParse_error(const char *msg)
|
|
|
|
|
{
|
|
|
|
|
sta::liberty_report->fileError(sta::liberty_filename, sta::liberty_line,
|
|
|
|
|
"%s.\n", msg);
|
|
|
|
|
libertyParseFlushBuffer();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|