OpenFPGA/libs/EXTERNAL/libblifparse/src/blif_parser.y

260 lines
8.6 KiB
Plaintext

/* C++ parsers require Bison 3 */
%require "3.0"
%language "C++"
/* Write-out tokens header file */
%defines
/* Use Bison's 'variant' to store values.
* This allows us to use non POD types (e.g.
* with constructors/destrictors), which is
* not possible with the default mode which
* uses unions.
*/
%define api.value.type variant
/*
* Use the 'complete' symbol type (i.e. variant)
* in the lexer
*/
%define api.token.constructor
/*
* Add a prefix the make_* functions used to
* create the symbols
*/
%define api.token.prefix {TOKEN_}
/*
* Use a re-entrant (no global vars) parser
*/
/*%define api.pure full*/
/* Wrap everything in our namespace */
%define api.namespace {blifparse}
/* Name the parser class */
%define parser_class_name {Parser}
/* Match the flex prefix */
%define api.prefix {blifparse_}
/* Extra checks for correct usage */
%define parse.assert
/* Enable debugging info */
%define parse.trace
/* Better error reporting */
%define parse.error verbose
/*
* Fixes inaccuracy in verbose error reporting.
* May be slow for some grammars.
*/
/*%define parse.lac full*/
/* Track locations */
/*%locations*/
/* Generate a table of token names */
%token-table
%lex-param {Lexer& lexer}
%parse-param {Lexer& lexer}
%parse-param {Callback& callback}
%code requires {
#include <memory>
#include "blifparse.hpp"
#include "blif_lexer_fwd.hpp"
}
%code top {
#include "blif_lexer.hpp"
//Bison calls blifparse_lex() to get the next token.
//We use the Lexer class as the interface to the lexer, so we
//re-defined the function to tell Bison how to get the next token.
static blifparse::Parser::symbol_type blifparse_lex(blifparse::Lexer& lexer) {
return lexer.next_token();
}
}
%{
#include <stdio.h>
#include "assert.h"
#include "blifparse.hpp"
#include "blif_common.hpp"
#include "blif_error.hpp"
using namespace blifparse;
%}
/* Declare constant */
%token DOT_NAMES ".names"
%token DOT_LATCH ".latch"
%token DOT_MODEL ".model"
%token DOT_SUBCKT ".subckt"
%token DOT_INPUTS ".inputs"
%token DOT_OUTPUTS ".outputs"
%token DOT_CLOCK ".clock"
%token DOT_END ".end"
%token DOT_BLACKBOX ".blackbox"
%token LATCH_FE "fe"
%token LATCH_RE "re"
%token LATCH_AH "ah"
%token LATCH_AL "al"
%token LATCH_AS "as"
%token NIL "NIL"
%token LATCH_INIT_2 "2"
%token LATCH_INIT_3 "3"
%token LOGIC_FALSE "0"
%token LOGIC_TRUE "1"
%token LOGIC_DONT_CARE "-"
%token EQ "="
%token EOL "end-of-line"
%token EOF 0 "end-of-file"
/*BLIF extensions */
%token DOT_CONN ".conn"
%token DOT_ATTR ".attr"
%token DOT_PARAM ".param"
%token DOT_CNAME ".cname"
/* declare variable tokens */
%token <std::string> STRING
/* declare types */
%type <SubCkt> subckt
%type <Names> names
%type <std::vector<std::string>> string_list
%type <std::vector<LogicValue>> so_cover_row
%type <LogicValue> logic_value
%type <LogicValue> latch_init
%type <std::string> latch_control
%type <LatchType> latch_type
/* BLIF Extensions */
%type <Conn> conn
%type <Cname> cname
%type <Attr> attr
%type <Param> param
/* Top level rule */
%start blif_data
%%
blif_data: /*empty*/ { }
| blif_data DOT_MODEL STRING EOL { callback.lineno(lexer.lineno()-1); callback.begin_model($3); }
| blif_data DOT_INPUTS string_list EOL { callback.lineno(lexer.lineno()-1); callback.inputs($3); }
| blif_data DOT_OUTPUTS string_list EOL { callback.lineno(lexer.lineno()-1); callback.outputs($3); }
| blif_data names { callback.lineno(lexer.lineno()-1); callback.names($2.nets, $2.so_cover); }
| blif_data subckt EOL {
if($2.ports.size() != $2.nets.size()) {
blif_error_wrap(callback ,lexer.lineno()-1, lexer.text(),
"Mismatched subckt port and net connection(s) size do not match"
" (%zu ports, %zu nets)", $2.ports.size(), $2.nets.size());
}
callback.lineno(lexer.lineno()-1);
callback.subckt($2.model, $2.ports, $2.nets);
}
| blif_data latch EOL { /*callback already called */ }
| blif_data DOT_BLACKBOX EOL { callback.lineno(lexer.lineno()-1); callback.blackbox(); }
| blif_data DOT_END EOL { callback.lineno(lexer.lineno()-1); callback.end_model(); }
| blif_data conn EOL { callback.lineno(lexer.lineno()-1); callback.conn($2.src, $2.dst); }
| blif_data cname EOL { callback.lineno(lexer.lineno()-1); callback.cname($2.name); }
| blif_data attr EOL { callback.lineno(lexer.lineno()-1); callback.attr($2.name, $2.value); }
| blif_data param EOL { callback.lineno(lexer.lineno()-1); callback.param($2.name, $2.value); }
| blif_data EOL { /* eat end-of-lines */}
;
names: DOT_NAMES string_list EOL { $$ = Names(); $$.nets = $2; }
| names so_cover_row EOL {
$$ = std::move($1);
if($$.nets.size() != $2.size()) {
blif_error_wrap(callback, lexer.lineno()-1, lexer.text(),
"Mismatched .names single-output cover row."
" names connected to %zu net(s), but cover row has %zu element(s)",
$$.nets.size(), $2.size());
}
$$.so_cover.push_back($2);
}
;
subckt: DOT_SUBCKT STRING { $$ = SubCkt(); $$.model = $2; }
| subckt STRING EQ STRING { $$ = std::move($1); $$.ports.push_back($2); $$.nets.push_back($4); }
;
latch: DOT_LATCH STRING STRING {
//Input and output only
callback.lineno(lexer.lineno());
callback.latch($2, $3, LatchType::UNSPECIFIED, "", LogicValue::UNKOWN);
}
| DOT_LATCH STRING STRING latch_type latch_control {
//Input, output, type and control
callback.lineno(lexer.lineno());
callback.latch($2, $3, $4, $5, LogicValue::UNKOWN);
}
| DOT_LATCH STRING STRING latch_type latch_control latch_init {
//Input, output, type, control and init-value
callback.lineno(lexer.lineno());
callback.latch($2, $3, $4, $5, $6);
}
| DOT_LATCH STRING STRING latch_init {
//Input, output, and init-value
callback.lineno(lexer.lineno());
callback.latch($2, $3, LatchType::UNSPECIFIED, "", $4);
}
;
latch_init: LOGIC_TRUE { $$ = LogicValue::TRUE; }
| LOGIC_FALSE { $$ = LogicValue::FALSE; }
| LATCH_INIT_2 { $$ = LogicValue::DONT_CARE; }
| LATCH_INIT_3 { $$ = LogicValue::UNKOWN; }
;
latch_control: STRING { $$ = $1;}
| NIL { $$ = ""; }
;
latch_type: LATCH_FE { $$ = LatchType::FALLING_EDGE; }
| LATCH_RE { $$ = LatchType::RISING_EDGE; }
| LATCH_AH { $$ = LatchType::ACTIVE_HIGH; }
| LATCH_AL { $$ = LatchType::ACTIVE_LOW; }
| LATCH_AS { $$ = LatchType::ASYNCHRONOUS; }
;
so_cover_row: logic_value { $$ = std::vector<LogicValue>(); $$.push_back($1); }
| so_cover_row logic_value { $$ = std::move($1); $$.push_back($2); }
;
logic_value: LOGIC_TRUE { $$ = LogicValue::TRUE; }
| LOGIC_FALSE { $$ = LogicValue::FALSE; }
| LOGIC_DONT_CARE { $$ = LogicValue::DONT_CARE; }
;
string_list: /*empty*/ { $$ = std::vector<std::string>(); }
| string_list STRING { $$ = std::move($1); $$.push_back($2); }
;
/*
* BLIF Extensions
*/
conn: DOT_CONN STRING STRING { $$ = Conn(); $$.src = $2; $$.dst = $3; }
cname: DOT_CNAME STRING { $$ = Cname(); $$.name = $2; }
attr: DOT_ATTR STRING STRING { $$ = Attr(); $$.name = $2; $$.value = $3; }
| DOT_ATTR STRING { $$ = Attr(); $$.name = $2; $$.value = ""; }
param: DOT_PARAM STRING STRING { $$ = Param(); $$.name = $2; $$.value = $3; }
| DOT_PARAM STRING { $$ = Param(); $$.name = $2; $$.value = ""; }
%%
void blifparse::Parser::error(const std::string& msg) {
blif_error_wrap(callback, lexer.lineno(), lexer.text(), msg.c_str());
}