-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathblif_parser.y
259 lines (216 loc) · 8.6 KB
/
blif_parser.y
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/* 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::UNKNOWN);
}
| DOT_LATCH STRING STRING latch_type latch_control {
//Input, output, type and control
callback.lineno(lexer.lineno());
callback.latch($2, $3, $4, $5, LogicValue::UNKNOWN);
}
| 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::UNKNOWN; }
;
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());
}