• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nickg / nvc / 25520612010

07 May 2026 08:34PM UTC coverage: 92.256% (+0.005%) from 92.251%
25520612010

push

github

nickg
Constant folding for Verilog << and >>>

70 of 77 new or added lines in 2 files covered. (90.91%)

109 existing lines in 3 files now uncovered.

77638 of 84155 relevant lines covered (92.26%)

641771.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.63
/src/vlog/vlog-parse.c
1
//
2
//  Copyright (C) 2024-2025  Nick Gasson
3
//
4
//  This program is free software: you can redistribute it and/or modify
5
//  it under the terms of the GNU General Public License as published by
6
//  the Free Software Foundation, either version 3 of the License, or
7
//  (at your option) any later version.
8
//
9
//  This program is distributed in the hope that it will be useful,
10
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
//  GNU General Public License for more details.
13
//
14
//  You should have received a copy of the GNU General Public License
15
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

18
#include "util.h"
19
#include "diag.h"
20
#include "ident.h"
21
#include "lib.h"
22
#include "object.h"
23
#include "parse.h"
24
#include "scan.h"
25
#include "vlog/vlog-node.h"
26
#include "vlog/vlog-phase.h"
27
#include "vlog/vlog-symtab.h"
28
#include "vlog/vlog-util.h"
29

30
#include <ctype.h>
31
#include <string.h>
32
#include <stdlib.h>
33
#include <assert.h>
34

35
static parse_state_t    state;
36
static vlog_kind_t      param_kind;
37
static vlog_net_kind_t  implicit_kind;
38
static vlog_symtab_t   *symtab;
39
static vlog_node_t      last_attr;
40
static vlog_node_t      atom_types[DT_BIT + 1];
41

42
extern loc_t yylloc;
43

44
#define BEGIN_WITH_HEAD(s, t)                            \
45
   EXTEND(s);                                            \
46
   state.start_loc = (t) ? *vlog_loc(t) : LOC_INVALID;   \
47

48
#define BEGIN(s)  BEGIN_WITH_HEAD(s, NULL)
49

50
static vlog_node_t p_statement_or_null(void);
51
static vlog_node_t p_expression(void);
52
static vlog_node_t p_constant_expression(void);
53
static vlog_node_t p_data_type(void);
54
static void p_list_of_variable_decl_assignments(vlog_node_t parent,
55
                                                vlog_node_t datatype);
56
static vlog_node_t p_variable_lvalue(void);
57
static vlog_node_t p_select(ident_t id);
58
static vlog_net_kind_t p_net_type(void);
59
static void p_module_or_generate_item(vlog_node_t mod);
60
static void p_block_item_declaration(vlog_node_t parent);
61
static vlog_node_t p_attribute_instance(void);
62
static vlog_node_t  p_drive_strength(void);
63
static vlog_strength_t p_strength0(void);
64
static vlog_strength_t p_strength1(void);
65

66
static vlog_node_t peek_reference(void)
179✔
67
{
68
   assert(peek() == tID);
179✔
69
   ident_t id = state.tokenq[state.tokenq_tail].lval.ident;
179✔
70
   return vlog_symtab_query(symtab, id);
179✔
71
}
72

73
static void vlog_parse_error_cb(void)
20✔
74
{
75
   vlog_symtab_suppress(symtab);
20✔
76
}
20✔
77

78
static void set_timescale(uint64_t unit_value, const char *unit_name,
21✔
79
                          uint64_t prec_value, const char *prec_name,
80
                          const loc_t *loc)
81
{
82
   // See IEEE 1800-2017 section 22.7 for rules
83

84
   struct {
21✔
85
      uint64_t    value;
86
      const char *name;
87
      uint64_t    parsed;
88
   } args[] = {
21✔
89
      { unit_value, unit_name },
90
      { prec_value, prec_name },
91
   };
92

93
   for (int i = 0; i < ARRAY_LEN(args); i++) {
63✔
94
      static const struct {
95
         const char *name;
96
         int64_t value;
97
      } valid_units[] = {
98
         { "s", INT64_C(60000000000000) },
99
         { "ms", 1000000000000 },
100
         { "us", 1000000000 },
101
         { "ns", 1000000 },
102
         { "ps", 1000 },
103
         { "fs", 1 },
104
      };
105

106
      bool name_valid = false;
220✔
107
      for (int j = 0; j < ARRAY_LEN(valid_units); j++) {
220✔
108
         if (strcmp(valid_units[j].name, args[i].name) == 0) {
219✔
109
            args[i].parsed = valid_units[j].value;
41✔
110
            name_valid = true;
41✔
111
            break;
41✔
112
         }
113
      }
114

115
      if (!name_valid)
41✔
116
         error_at(loc, "invalid time unit name '%s'", args[i].name);
1✔
117

118
      if (args[i].value != 1 && args[i].value != 10 && args[i].value != 100) {
42✔
119
         diag_t *d = diag_new(DIAG_ERROR, loc);
1✔
120
         diag_printf(d, "invalid order of magnitude in `timescale directive");
1✔
121
         diag_hint(d, NULL, "the valid values are 1, 10, and 100");
1✔
122
         diag_emit(d);
1✔
123
      }
124

125
      args[i].parsed *= args[i].value;
42✔
126
   }
127

128
   // TODO: do something with parsed scale/precision
129
}
21✔
130

131
static void skip_over_attributes(void)
9,711✔
132
{
133
   while (peek() == tATTRBEGIN)
9,731✔
134
      last_attr = p_attribute_instance();
20✔
135
}
9,711✔
136

137
static void optional_attributes(void)
70,243✔
138
{
139
   if (peek() == tATTRBEGIN) {
70,243✔
140
      // If the current token is (* and there is a saved attribute
141
      // instance from skip_over_attributes() then the attribute must
142
      // have been placed incorrectly as there were other tokens between
143
      // the last closing *) and this
144
      if (last_attr != NULL)
7✔
145
         parse_error(vlog_loc(last_attr), "attribute instance is not "
1✔
146
                     "allowed here");
147

148
      do {
7✔
149
         (void)p_attribute_instance();
7✔
150
      } while (peek() == tATTRBEGIN);
7✔
151
   }
152

153
   last_attr = NULL;
70,243✔
154
}
70,243✔
155

156
static vlog_node_t dummy_expression(void)
×
157
{
158
   vlog_node_t v = vlog_new(V_NUMBER);
×
159
   vlog_set_number(v, number_from_bool(false));
×
160
   return v;
×
161
}
162

163
static vlog_node_t logic_type(void)
17✔
164
{
165
   vlog_node_t v = vlog_new(V_DATA_TYPE);
17✔
166
   vlog_set_subkind(v, DT_LOGIC);
17✔
167
   return v;
17✔
168
}
169

170
static vlog_node_t implicit_type(void)
80✔
171
{
172
   vlog_node_t v = vlog_new(V_DATA_TYPE);
80✔
173
   vlog_set_subkind(v, DT_IMPLICIT);
80✔
174
   return v;
80✔
175
}
176

177
static vlog_node_t make_integer_atom_type(data_type_t dt)
248✔
178
{
179
   if (atom_types[dt] == NULL) {
248✔
180
      int width;
166✔
181
      switch (dt) {
166✔
182
      case DT_BYTE:     width = 8; break;
183
      case DT_SHORTINT: width = 16; break;
5✔
184
      case DT_INT:      width = 32; break;
32✔
185
      case DT_LONGINT:  width = 64; break;
1✔
186
      case DT_INTEGER:  width = 32; break;
116✔
187
      case DT_TIME:     width = 64; break;
2✔
188
      default: should_not_reach_here();
189
      }
190

191
      vlog_node_t left = vlog_new(V_NUMBER);
166✔
192
      vlog_set_number(left, number_from_int(width - 1));
166✔
193

194
      vlog_node_t right = vlog_new(V_NUMBER);
166✔
195
      vlog_set_number(right, number_from_int(0));
166✔
196

197
      vlog_node_t r = vlog_new(V_DIMENSION);
166✔
198
      vlog_set_subkind(r, V_DIM_PACKED);
166✔
199
      vlog_set_left(r, left);
166✔
200
      vlog_set_right(r, right);
166✔
201

202
      atom_types[dt] = r;
166✔
203
   }
204

205
   vlog_node_t v = vlog_new(V_DATA_TYPE);
248✔
206
   vlog_set_subkind(v, dt);
248✔
207
   vlog_add_range(v, atom_types[dt]);
248✔
208

209
   vlog_set_loc(v, &state.last_loc);
248✔
210
   return v;
248✔
211
}
212

213
static ident_t default_label(const char *prefix)
1,509✔
214
{
215
   return ident_sprintf("%s#%d#%d", prefix, state.last_loc.first_line,
3,018✔
216
                        state.last_loc.first_column);
1,509✔
217
}
218

219
static vlog_gate_kind_t get_gate_kind(token_t tok)
38✔
220
{
221
   switch (tok) {
38✔
222
   case tAND:      return V_GATE_AND;
223
   case tNAND:     return V_GATE_NAND;
4✔
224
   case tOR:       return V_GATE_OR;
10✔
225
   case tNOR:      return V_GATE_NOR;
×
226
   case tXOR:      return V_GATE_XOR;
4✔
227
   case tXNOR:     return V_GATE_XNOR;
×
228
   case tNOT:      return V_GATE_NOT;
5✔
229
   case tNOTIF0:   return V_GATE_NOTIF0;
×
230
   case tNOTIF1:   return V_GATE_NOTIF1;
×
231
   case tBUF:      return V_GATE_BUF;
6✔
232
   case tBUFIF0:   return V_GATE_BUFIF0;
1✔
233
   case tBUFIF1:   return V_GATE_BUFIF1;
×
234
   case tTRAN:     return V_GATE_TRAN;
1✔
235
   case tTRANIF0:  return V_GATE_TRANIF0;
×
236
   case tTRANIF1:  return V_GATE_TRANIF1;
1✔
237
   case tRTRAN:    return V_GATE_RTRAN;
×
238
   case tRTRANIF0: return V_GATE_RTRANIF0;
×
239
   case tRTRANIF1: return V_GATE_RTRANIF1;
×
240
   default:        should_not_reach_here();
241
   }
242
}
243

244
static void declare_port(vlog_node_t mod, vlog_node_t port)
459✔
245
{
246
   ident_t id = vlog_ident(port);
459✔
247

248
   const int nports = vlog_ports(mod);
459✔
249
   bool found = false;
459✔
250
   for (int i = 0; i < nports; i++) {
3,284✔
251
      vlog_node_t p = vlog_port(mod, i);
2,825✔
252
      if (vlog_ident(p) == id) {
2,825✔
253
         vlog_set_ref(p, port);
459✔
254
         found = true;
459✔
255
      }
256
   }
257

258
   if (!found) {
459✔
259
      diag_t *d = diag_new(DIAG_ERROR, vlog_loc(port));
2✔
260
      diag_printf(d, "'%s' does not appear in module port list", istr(id));
2✔
261
      diag_hint(d, vlog_loc(mod), "module declaration for '%s'",
2✔
262
                istr(vlog_ident2(mod)));
263
      diag_emit(d);
2✔
264
   }
265
}
459✔
266

267
static bool scan_block_item_declaration(void)
2,045✔
268
{
269
   return scan(tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM, tSVINT, tINTEGER,
2,045✔
270
               tSVREAL, tSHORTREAL, tREALTIME, tBIT, tLOGIC, tSHORTINT, tTIME);
271
}
272

273
static bool scan_tf_item_declaration(void)
161✔
274
{
275
   return scan(tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM, tSVINT, tINTEGER,
161✔
276
               tSVREAL, tSHORTREAL, tREALTIME, tBIT, tLOGIC, tSHORTINT, tTIME,
277
               tINPUT, tOUTPUT);
278
}
279

280
static ident_t p_identifier(void)
41,955✔
281
{
282
   if (consume(tID))
41,955✔
283
      return state.last_lval.ident;
41,954✔
284
   else
285
      return error_marker();
1✔
286
}
287

288
static void p_external_identifier(ident_t *id, ident_t *ext)
1,460✔
289
{
290
   if (consume(tID)) {
1,460✔
291
      *id = state.last_lval.ident;
1,460✔
292

293
      LOCAL_TEXT_BUF tb = tb_new();
1,460✔
294
      tb_istr(tb, state.last_lval.ident);
1,460✔
295
      tb_upcase(tb);
1,460✔
296

297
      *ext = ident_new(tb_get(tb));
1,460✔
298
   }
299
   else
300
      *id = *ext = error_marker();
×
301
}
1,460✔
302

303
static ident_t p_system_tf_identifier(void)
8,096✔
304
{
305
   if (consume(tSYSTASK))
8,096✔
306
      return state.last_lval.ident;
8,096✔
307
   else
308
      return error_marker();
×
309
}
310

311
static void p_attr_spec(void)
27✔
312
{
313
   // attr_name [ = constant_expression ]
314

315
   BEGIN("attribute specification");
54✔
316

317
   (void)p_identifier();
27✔
318

319
   if (optional(tEQ))
27✔
320
      (void)p_constant_expression();
1✔
321
}
27✔
322

323
static vlog_node_t p_attribute_instance(void)
27✔
324
{
325
   // (* attr_spec { , attr_spec } *)
326

327
   BEGIN("attribute instance");
54✔
328

329
   consume(tATTRBEGIN);
27✔
330

331
   vlog_node_t v = vlog_new(V_ATTR_INST);
27✔
332

333
   do {
27✔
334
      p_attr_spec();
27✔
335
   } while (optional(tCOMMA));
27✔
336

337
   consume(tATTREND);
27✔
338

339
   vlog_set_loc(v, CURRENT_LOC);
27✔
340
   return v;
27✔
341
}
342

343
static vlog_node_t p_unsigned_number(void)
16,347✔
344
{
345
   // decimal_digit { _ | decimal_digit }
346

347
   BEGIN("unsigned number");
32,694✔
348

349
   number_t n;
16,347✔
350
   if (consume(tUNSNUM)) {
16,347✔
351
      n = number_new(state.last_lval.str, CURRENT_LOC);
16,347✔
352
      free(state.last_lval.str);
16,347✔
353
   }
354
   else
355
      n = number_from_int(0);
×
356

357
   vlog_node_t v = vlog_new(V_NUMBER);
16,347✔
358
   vlog_set_number(v, n);
16,347✔
359
   vlog_set_loc(v, CURRENT_LOC);
16,347✔
360
   return v;
16,347✔
361
}
362

363
static vlog_node_t p_integral_number(void)
31,610✔
364
{
365
   // decimal_number | octal_number | binary_number | hex_number
366

367
   BEGIN("integral number");
63,220✔
368

369
   if (peek() == tUNSNUM)
31,610✔
370
      return p_unsigned_number();
11,877✔
371
   else {
372
      number_t n;
19,733✔
373
      if (consume(tNUMBER)) {
19,733✔
374
         n = number_new(state.last_lval.str, &state.last_loc);
19,732✔
375
         free(state.last_lval.str);
19,732✔
376
      }
377
      else
378
         n = number_from_int(0);
1✔
379

380
      vlog_node_t v = vlog_new(V_NUMBER);
19,733✔
381
      vlog_set_number(v, n);
19,733✔
382
      vlog_set_loc(v, CURRENT_LOC);
19,733✔
383
      return v;
19,733✔
384
   }
385
}
386

387
static vlog_node_t p_real_number(void)
302✔
388
{
389
   // fixed_point_number
390
   //   | unsigned_number [ . unsigned_number ] exp [ sign ] unsigned_number
391

392
   BEGIN("real number");
604✔
393

394
   consume(tREAL);
302✔
395

396
   vlog_node_t v = vlog_new(V_REAL);
302✔
397
   vlog_set_dval(v, state.last_lval.real);
302✔
398
   vlog_set_loc(v, CURRENT_LOC);
302✔
399
   return v;
302✔
400
}
401

402
static vlog_node_t p_number(void)
31,901✔
403
{
404
   // integral_number | real_number
405

406
   BEGIN("number");
63,802✔
407

408
   if (peek() == tREAL)
31,901✔
409
      return p_real_number();
297✔
410
   else
411
      return p_integral_number();
31,604✔
412
}
413

414
static vlog_node_t p_string_literal(void)
4,735✔
415
{
416
   // " { Any_ASCII_Characters } "
417

418
   BEGIN("string literal");
9,470✔
419

420
   number_t n;
4,735✔
421
   if (consume(tSTRING)) {
4,735✔
422
      text_buf_t *tb = state.last_lval.text;
4,735✔
423
      n = number_from_string(tb_get(tb), tb_len(tb));
4,735✔
424
      tb_free(tb);
4,735✔
425
   }
426
   else
427
      should_not_reach_here();
428

429
   vlog_node_t v = vlog_new(V_STRING);
4,735✔
430
   vlog_set_number(v, n);
4,735✔
431
   vlog_set_loc(v, CURRENT_LOC);
4,735✔
432
   return v;
9,470✔
433
}
434

435
static vlog_node_t p_primary_literal(void)
36,636✔
436
{
437
   // number | time_literal | unbased_unsized_literal | string_literal
438

439
   BEGIN("primary literal");
73,272✔
440

441
   switch (peek()) {
36,636✔
442
   case tNUMBER:
31,901✔
443
   case tUNSNUM:
444
   case tREAL:
445
      return p_number();
31,901✔
446
   case tSTRING:
4,735✔
447
      return p_string_literal();
4,735✔
448
   default:
×
449
      one_of(tNUMBER, tUNSNUM, tREAL, tSTRING);
×
450
      return dummy_expression();
×
451
   }
452
}
453

454
static vlog_node_t p_constant_select(ident_t id)
548✔
455
{
456
   // [ { . member_identifier constant_bit_select } . member_identifier ]
457
   //    constant_bit_select [ [ constant_part_select_range ] ]
458

459
   EXTEND("constant select");
1,096✔
460

461
   // Checked for constant-ness later
462
   return p_select(id);
548✔
463
}
464

465
static vlog_node_t p_constant_expression(void)
7,370✔
466
{
467
   // constant_primary | unary_operator { attribute_instance } constant_primary
468
   //   | constant_expression binary_operator { attribute_instance }
469
   //       constant_expression
470
   //   | constant_expression ? { attribute_instance }
471
   //       constant_expression : constant_expression
472

473
   BEGIN("constant expression");
14,740✔
474

475
   // Checked for constant-ness later
476
   return p_expression();
7,370✔
477
}
478

479
static void p_constant_range(vlog_node_t *left, vlog_node_t *right)
3,467✔
480
{
481
   // constant_expression : constant_expression
482

483
   BEGIN("constant range");
6,934✔
484

485
   *left = p_constant_expression();
3,467✔
486

487
   consume(tCOLON);
3,467✔
488

489
   *right = p_constant_expression();
3,467✔
490
}
3,467✔
491

492
static vlog_node_t p_constant_range_expression(void)
2✔
493
{
494
   // constant_expression | constant_part_select_range
495

496
   BEGIN("constant range expression");
4✔
497

498
   return p_constant_expression();
2✔
499
}
500

501
static vlog_node_t p_constant_mintypmax_expression(void)
8✔
502
{
503
   // constant_expression
504
   //   | constant_expression : constant_expression : constant_expression
505

506
   return p_constant_expression();
8✔
507
}
508

509
static vlog_node_t p_packed_dimension(void)
3,382✔
510
{
511
   // [ constant_range ] | unsized_dimension
512

513
   BEGIN("packed dimension");
6,764✔
514

515
   consume(tLSQUARE);
3,382✔
516

517
   vlog_node_t left, right;
3,382✔
518
   p_constant_range(&left, &right);
3,382✔
519

520
   consume(tRSQUARE);
3,382✔
521

522
   vlog_node_t v = vlog_new(V_DIMENSION);
3,382✔
523
   vlog_set_subkind(v, V_DIM_PACKED);
3,382✔
524
   vlog_set_left(v, left);
3,382✔
525
   vlog_set_right(v, right);
3,382✔
526
   vlog_set_loc(v, CURRENT_LOC);
3,382✔
527

528
   return v;
3,382✔
529
}
530

531
static vlog_node_t p_unpacked_dimension(void)
85✔
532
{
533
   // [ constant_range ] | [ constant_expression ]
534

535
   BEGIN("unpacked dimension");
170✔
536

537
   consume(tLSQUARE);
85✔
538

539
   vlog_node_t left, right;
85✔
540
   p_constant_range(&left, &right);
85✔
541

542
   consume(tRSQUARE);
85✔
543

544
   vlog_node_t v = vlog_new(V_DIMENSION);
85✔
545
   vlog_set_subkind(v, V_DIM_UNPACKED);
85✔
546
   vlog_set_left(v, left);
85✔
547
   vlog_set_right(v, right);
85✔
548
   vlog_set_loc(v, CURRENT_LOC);
85✔
549

550
   return v;
85✔
551
}
552

553
static vlog_node_t p_data_type_or_void(void)
29✔
554
{
555
   // data_type | void
556

557
   BEGIN("data type or void");
58✔
558

559
   if (optional(tVOID))
29✔
560
      return NULL;
561
   else
562
      return p_data_type();
28✔
563
}
564

565
static void p_struct_union_member(vlog_node_t v)
12✔
566
{
567
   // { attribute_instance } [ random_qualifier ] data_type_or_void
568
   //    list_of_variable_decl_assignments ;
569

570
   BEGIN("struct or union member");
24✔
571

572
   optional_attributes();
12✔
573

574
   vlog_node_t dt = p_data_type_or_void();
12✔
575
   p_list_of_variable_decl_assignments(v, dt);
12✔
576

577
   consume(tSEMI);
12✔
578
}
12✔
579

580
static void p_enum_name_declaration(vlog_node_t parent)
57✔
581
{
582
   // enum_identifier [ [ integral_number [ : integral_number ] ] ]
583
   //   [ = constant_expression ]
584

585
   BEGIN("enum name declaration");
114✔
586

587
   vlog_node_t v = vlog_new(V_ENUM_NAME);
57✔
588
   vlog_set_ident(v, p_identifier());
57✔
589
   vlog_set_type(v, parent);
57✔
590

591
   if (optional(tEQ))
57✔
592
      vlog_set_value(v, p_constant_expression());
19✔
593

594
   vlog_add_decl(parent, v);
57✔
595

596
   vlog_set_loc(v, CURRENT_LOC);
57✔
597
   vlog_symtab_put(symtab, v);
57✔
598
}
57✔
599

600
static vlog_node_t p_integer_atom_type(void)
225✔
601
{
602
   // byte | shortint | int | longint | integer | time
603

604
   BEGIN("integer atom type");
450✔
605

606
   data_type_t dt = DT_BYTE;
225✔
607
   switch (one_of(tBYTE, tSHORTINT, tSVINT, tLONGINT, tINTEGER, tTIME)) {
225✔
608
   case tBYTE:     dt = DT_BYTE; break;
609
   case tSHORTINT: dt = DT_SHORTINT; break;
610
   case tSVINT:    dt = DT_INT; break;
611
   case tLONGINT:  dt = DT_LONGINT; break;
612
   case tINTEGER:  dt = DT_INTEGER; break;
613
   case tTIME:     dt = DT_TIME; break;
614
   }
615

616
   return make_integer_atom_type(dt);
225✔
617
}
618

619
static vlog_node_t p_integer_vector_type(void)
3,155✔
620
{
621
   //  bit | logic | reg
622

623
   BEGIN("integer vector type");
6,310✔
624

625
   data_type_t dt = DT_LOGIC;
3,155✔
626
   switch (one_of(tBIT, tLOGIC, tREG)) {
3,155✔
627
   case tBIT:    dt = DT_BIT; break;
14✔
628
   case tLOGIC:
629
   case tREG:    dt = DT_LOGIC; break;
630
   }
631

632
   vlog_node_t v = vlog_new(V_DATA_TYPE);
3,155✔
633
   vlog_set_subkind(v, dt);
3,155✔
634
   vlog_set_loc(v, &state.last_loc);
3,155✔
635
   return v;
3,155✔
636
}
637

638
static vlog_node_t p_non_integer_type(void)
44✔
639
{
640
   // shortreal | real | realtime
641

642
   BEGIN("non-integer type");
88✔
643

644
   data_type_t dt = DT_REAL;
44✔
645
   switch (one_of(tSVREAL, tSHORTREAL, tREALTIME)) {
44✔
646
   case tSVREAL:    dt = DT_REAL; break;
647
   case tSHORTREAL: dt = DT_SHORTREAL; break;
2✔
648
   case tREALTIME:  dt = DT_REALTIME; break;
1✔
649
   }
650

651
   vlog_node_t v = vlog_new(V_DATA_TYPE);
44✔
652
   vlog_set_subkind(v, dt);
44✔
653
   vlog_set_loc(v, &state.last_loc);
44✔
654
   return v;
44✔
655
}
656

657
static vlog_node_t p_struct_union(void)
7✔
658
{
659
   // struct | union [ tagged ]
660

661
   BEGIN("struct or union");
14✔
662

663
   switch (one_of(tSTRUCT, tUNION)) {
7✔
664
   case tUNION:
2✔
665
      {
666
         vlog_node_t v = vlog_new(V_UNION_DECL);
2✔
667
         optional(tTAGGED);
2✔
668
         return v;
2✔
669
      }
670
   case tSTRUCT:
5✔
671
   default:
672
      return vlog_new(V_STRUCT_DECL);
5✔
673
   }
674
}
675

676
static vlog_flags_t p_signing(void)
113✔
677
{
678
   // signed | unsigned
679

680
   BEGIN("signing");
226✔
681

682
   switch (one_of(tSIGNED, tUNSIGNED)) {
113✔
683
   case tSIGNED: return VLOG_F_SIGNED;
684
   default: return 0;
25✔
685
   }
686
}
687

688
static vlog_node_t p_enum_base_type(void)
13✔
689
{
690
   // integer_atom_type [ signing ]
691
   //   | integer_vector_type [ signing ] [ packed_dimension ]
692
   //   | type_identifier [ packed_dimension ]
693

694
   BEGIN("enum base type");
26✔
695

696
   switch (peek()) {
13✔
697
   case tBYTE:
11✔
698
   case tSHORTINT:
699
   case tSVINT:
700
   case tLONGINT:
701
   case tINTEGER:
702
   case tTIME:
703
      {
704
         vlog_node_t v = p_integer_atom_type();
11✔
705

706
         if (scan(tSIGNED, tUNSIGNED))
11✔
707
            vlog_set_flags(v, p_signing());
×
708
         else
709
            vlog_set_flags(v, VLOG_F_SIGNED);
11✔
710

711
         return v;
712
      }
713

714
   case tBIT:
2✔
715
   case tLOGIC:
716
   case tREG:
717
      {
718
         vlog_node_t v = p_integer_vector_type();
2✔
719

720
         if (scan(tSIGNED, tUNSIGNED))
2✔
721
            vlog_set_flags(v, p_signing());
×
722

723
         if (scan(tLSQUARE))
2✔
724
            p_packed_dimension();
2✔
725

726
         return v;
727
      }
728

729
   default:
×
730
      p_identifier();
×
731

732
      if (scan(tLSQUARE))
×
733
         p_packed_dimension();
×
734

735
      return NULL;
736
   }
737
}
738

739
static vlog_node_t p_data_type(void)
3,465✔
740
{
741
   // integer_vector_type [ signing ] { packed_dimension }
742
   //   | integer_atom_type [ signing ] | non_integer_type
743
   //   | struct_union [ packed [ signing ] ]
744
   //       { struct_union_member { struct_union_member } } { packed_dimension }
745
   //   | enum [ enum_base_type ] { enum_name_declaration
746
   //       { , enum_name_declaration } } { packed_dimension }
747
   //   | string | chandle
748
   //   | virtual [ interface ] interface_identifier
749
   //       [ parameter_value_assignment ] [ . modport_identifier ]
750
   //   | [ class_scope | package_scope ] type_identifier { packed_dimension }
751
   //   | class_type | event | ps_covergroup_identifier | type_reference
752

753
   BEGIN("data type");
6,930✔
754

755
   switch (peek()) {
3,465✔
756
   case tBIT:
3,153✔
757
   case tLOGIC:
758
   case tREG:
759
      {
760
         vlog_node_t v = p_integer_vector_type();
3,153✔
761

762
         if (scan(tSIGNED, tUNSIGNED))
3,153✔
763
            vlog_set_flags(v, p_signing());
49✔
764

765
         while (peek() == tLSQUARE)
5,865✔
766
            vlog_add_range(v, p_packed_dimension());
2,712✔
767

768
         return v;
769
      }
770

771
   case tBYTE:
214✔
772
   case tSHORTINT:
773
   case tSVINT:
774
   case tLONGINT:
775
   case tINTEGER:
776
   case tTIME:
777
      {
778
         vlog_node_t v = p_integer_atom_type();
214✔
779

780
         if (scan(tSIGNED, tUNSIGNED))
214✔
781
            vlog_set_flags(v, p_signing());
1✔
782
         else
783
            vlog_set_flags(v, VLOG_F_SIGNED);
213✔
784

785
         return v;
786
      }
787

788
   case tSVREAL:
44✔
789
   case tREALTIME:
790
   case tSHORTREAL:
791
      return p_non_integer_type();
44✔
792

793
   case tSTRUCT:
7✔
794
   case tUNION:
795
      {
796
         vlog_node_t v = p_struct_union();
7✔
797

798
         (void)optional(tPACKED);
7✔
799

800
         consume(tLBRACE);
7✔
801

802
         vlog_symtab_push(symtab, v);
7✔
803

804
         do {
12✔
805
            p_struct_union_member(v);
12✔
806
         } while (not_at_token(tRBRACE));
12✔
807

808
         vlog_symtab_pop(symtab);
7✔
809

810
         consume(tRBRACE);
7✔
811

812
         if (peek() == tLSQUARE)
7✔
813
            vlog_add_range(v, p_packed_dimension());
×
814

815
         vlog_set_loc(v, CURRENT_LOC);
7✔
816
         return v;
7✔
817
      }
818

819
   case tENUM:
22✔
820
      {
821
         consume(tENUM);
22✔
822

823
         vlog_node_t v = vlog_new(V_ENUM_DECL);
22✔
824

825
         if (peek() != tLBRACE)
22✔
826
            vlog_set_type(v, p_enum_base_type());
13✔
827
         else {
828
            vlog_node_t dt = make_integer_atom_type(DT_INT);
9✔
829
            vlog_set_flags(dt, VLOG_F_SIGNED);
9✔
830

831
            vlog_set_type(v, dt);
9✔
832
         }
833

834
         consume(tLBRACE);
22✔
835

836
         do {
57✔
837
            p_enum_name_declaration(v);
57✔
838
         } while (optional(tCOMMA));
57✔
839

840
         consume(tRBRACE);
22✔
841

842
         while (peek() == tLSQUARE)
24✔
843
            vlog_add_range(v, p_packed_dimension());
2✔
844

845
         vlog_set_loc(v, CURRENT_LOC);
22✔
846
         return v;
22✔
847
      }
848

849
   case tEVENT:
1✔
850
      {
851
         consume(tEVENT);
1✔
852

853
         vlog_node_t v = vlog_new(V_DATA_TYPE);
1✔
854
         vlog_set_subkind(v, DT_EVENT);
1✔
855
         vlog_set_loc(v, &state.last_loc);
1✔
856

857
         return v;
1✔
858
      }
859

860
   case tID:
20✔
861
      {
862
         ident_t id = p_identifier();
20✔
863
         vlog_node_t dt = vlog_symtab_query(symtab, id);
20✔
864
         if (dt == NULL) {
20✔
865
            error_at(&state.last_loc, "no data type declaration for '%s'",
1✔
866
                     istr(id));
867
            return logic_type();
1✔
868
         }
869
         else if (!is_data_type(dt)) {
19✔
870
            diag_t *d = diag_new(DIAG_ERROR, &state.last_loc);
1✔
871
            diag_printf(d, "'%s' is not a data type", istr(id));
1✔
872
            diag_hint(d, vlog_loc(dt), "'%s' declared here", istr(id));
1✔
873
            diag_emit(d);
1✔
874

875
            return logic_type();
1✔
876
         }
877
         else
878
            return dt;
879
      }
880

881
   case tSTRINGK:
4✔
882
      {
883
         consume(tSTRINGK);
4✔
884

885
         vlog_node_t v = vlog_new(V_DATA_TYPE);
4✔
886
         vlog_set_subkind(v, DT_STRING);
4✔
887
         vlog_set_loc(v, &state.last_loc);
4✔
888

889
         return v;
4✔
890
      }
891

892
   default:
×
893
      one_of(tBIT, tLOGIC, tREG, tBYTE, tSHORTINT, tSVINT, tLONGINT, tINTEGER,
×
894
             tTIME, tSVREAL, tREALTIME, tSHORTREAL, tSTRUCT, tUNION, tENUM,
895
             tEVENT, tID, tSTRINGK);
896
      return logic_type();
×
897
   }
898
}
899

900
static vlog_node_t p_implicit_data_type(void)
1,562✔
901
{
902
   // [ signing ] { packed_dimension }
903

904
   BEGIN("implicit data type");
3,124✔
905

906
   vlog_node_t v = vlog_new(V_DATA_TYPE);
1,562✔
907
   vlog_set_subkind(v, DT_IMPLICIT);
1,562✔
908

909
   if (scan(tSIGNED, tUNSIGNED))
1,562✔
910
      vlog_set_flags(v, p_signing());
63✔
911

912
   while (peek() == tLSQUARE)
2,227✔
913
      vlog_add_range(v, p_packed_dimension());
665✔
914

915
   vlog_set_loc(v, CURRENT_LOC);
1,562✔
916
   return v;
1,562✔
917
}
918

919
static vlog_node_t p_data_type_or_implicit(void)
4,905✔
920
{
921
   // data_type | implicit_data_type
922

923
   BEGIN("data type or implicit");
9,810✔
924

925
   switch (peek()) {
4,905✔
926
   case tID:
855✔
927
      if (peek_nth(2) == tID)
855✔
928
         return p_data_type();
20✔
929
      else
930
         return p_implicit_data_type();
835✔
931
      break;
3,378✔
932
   case tREG:
3,378✔
933
   case tSTRUCT:
934
   case tUNION:
935
   case tENUM:
936
   case tSVINT:
937
   case tINTEGER:
938
   case tSVREAL:
939
   case tSHORTREAL:
940
   case tREALTIME:
941
   case tTIME:
942
   case tLOGIC:
943
   case tBIT:
944
   case tSHORTINT:
945
   case tLONGINT:
946
   case tBYTE:
947
   case tEVENT:
948
   case tSTRINGK:
949
      return p_data_type();
3,378✔
950
   default:
672✔
951
      return p_implicit_data_type();
672✔
952
   }
953
}
954

955
static void p_net_port_type(vlog_net_kind_t *kind, vlog_node_t *dt)
499✔
956
{
957
   // [ net_type ] data_type_or_implicit | net_type_identifier
958
   //   | interconnect implicit_data_type
959

960
   BEGIN("net port type");
998✔
961

962
   if (scan(tSUPPLY0, tSUPPLY1, tTRI, tTRIAND, tTRIOR, tTRIREG,
499✔
963
            tTRI0, tTRI1, tUWIRE, tWIRE, tWAND, tWOR))
964
      *kind = p_net_type();
86✔
965
   else
966
      *kind = V_NET_WIRE;
413✔
967

968
   *dt = p_data_type_or_implicit();
499✔
969
}
499✔
970

971
static vlog_node_t p_var_data_type(void)
24✔
972
{
973
   // data_type | var data_type_or_implicit
974

975
   BEGIN("var data type");
48✔
976

977
   return p_data_type();
24✔
978
}
979

980
static vlog_node_t p_variable_port_type(void)
24✔
981
{
982
   // var_data_type
983

984
   BEGIN("variable port type");
48✔
985

986
   return p_var_data_type();
24✔
987
}
988

989
static void p_list_of_port_identifiers(vlog_node_t mod, v_port_kind_t kind,
407✔
990
                                       vlog_node_t datatype)
991
{
992
   // port_identifier { unpacked_dimension }
993
   //    { , port_identifier { unpacked_dimension } }
994

995
   BEGIN("list of port identifiers");
814✔
996

997
   do {
435✔
998
      ident_t id, ext;
435✔
999
      p_external_identifier(&id, &ext);
435✔
1000

1001
      vlog_node_t v = vlog_new(V_PORT_DECL);
435✔
1002
      vlog_set_subkind(v, kind);
435✔
1003
      vlog_set_ident(v, id);
435✔
1004
      vlog_set_ident2(v, ext);
435✔
1005
      vlog_set_type(v, datatype);
435✔
1006
      vlog_set_loc(v, &state.last_loc);
435✔
1007

1008
      vlog_add_decl(mod, v);
435✔
1009
      vlog_symtab_put(symtab, v);
435✔
1010

1011
      declare_port(mod, v);
435✔
1012
   } while (optional(tCOMMA));
435✔
1013
}
407✔
1014

1015
static void p_list_of_variable_port_identifiers(vlog_node_t mod,
24✔
1016
                                                v_port_kind_t kind,
1017
                                                vlog_node_t datatype)
1018
{
1019
   // port_identifier { variable_dimension } [ = constant_expression ]
1020
   //   { , port_identifier { variable_dimension } [ = constant_expression ] }
1021

1022
   BEGIN("list of variable port identifiers");
48✔
1023

1024
   do {
24✔
1025
      ident_t id, ext;
24✔
1026
      p_external_identifier(&id, &ext);
24✔
1027

1028
      vlog_node_t v = vlog_new(V_PORT_DECL);
24✔
1029
      vlog_set_subkind(v, kind);
24✔
1030
      vlog_set_ident(v, id);
24✔
1031
      vlog_set_ident2(v, ext);
24✔
1032
      vlog_set_type(v, datatype);
24✔
1033
      vlog_set_loc(v, &state.last_loc);
24✔
1034

1035
      if (optional(tEQ))
24✔
1036
         vlog_set_value(v, p_constant_expression());
4✔
1037

1038
      vlog_add_decl(mod, v);
24✔
1039
      vlog_symtab_put(symtab, v);
24✔
1040

1041
      declare_port(mod, v);
24✔
1042
   } while (optional(tCOMMA));
24✔
1043
}
24✔
1044

1045
static void p_inout_declaration(vlog_node_t mod)
1✔
1046
{
1047
   // inout net_port_type list_of_port_identifiers
1048

1049
   BEGIN("inout declaration");
2✔
1050

1051
   consume(tINOUT);
1✔
1052

1053
   vlog_node_t dt;
1✔
1054
   vlog_net_kind_t kind;
1✔
1055
   p_net_port_type(&kind, &dt);
1✔
1056

1057
   p_list_of_port_identifiers(mod, V_PORT_INOUT, dt);
1✔
1058
}
1✔
1059

1060
static void p_input_declaration(vlog_node_t mod)
233✔
1061
{
1062
   // input net_port_type list_of_port_identifiers
1063
   //   | input variable_port_type list_of_variable_identifiers
1064

1065
   BEGIN("input declaration");
466✔
1066

1067
   consume(tINPUT);
233✔
1068

1069
   vlog_node_t dt;
233✔
1070
   vlog_net_kind_t kind;
233✔
1071
   switch (peek()) {
233✔
1072
   case tREG:
×
1073
      dt = p_variable_port_type();
×
1074
      p_list_of_variable_port_identifiers(mod, V_PORT_INPUT, dt);
×
1075
      break;
×
1076
   default:
233✔
1077
      p_net_port_type(&kind, &dt);
233✔
1078
      p_list_of_port_identifiers(mod, V_PORT_INPUT, dt);
233✔
1079
      break;
233✔
1080
   }
1081
}
233✔
1082

1083
static void p_output_declaration(vlog_node_t mod)
197✔
1084
{
1085
   // output net_port_type list_of_port_identifiers
1086
   //   | output variable_port_type list_of_variable_port_identifiers
1087

1088
   BEGIN("output declaration");
394✔
1089

1090
   consume(tOUTPUT);
197✔
1091

1092
   switch (peek()) {
197✔
1093
   case tREG:
24✔
1094
      {
1095
         vlog_node_t dt = p_variable_port_type();
24✔
1096
         p_list_of_variable_port_identifiers(mod, V_PORT_OUTPUT, dt);
24✔
1097
      }
1098
      break;
24✔
1099
   default:
173✔
1100
      {
1101
         vlog_node_t dt;
173✔
1102
         vlog_net_kind_t kind;
173✔
1103
         p_net_port_type(&kind, &dt);
173✔
1104
         p_list_of_port_identifiers(mod, V_PORT_OUTPUT, dt);
173✔
1105
      }
1106
      break;
173✔
1107
   }
1108
}
197✔
1109

1110
static void p_port_declaration(vlog_node_t mod)
431✔
1111
{
1112
   // { attribute_instance } inout_declaration
1113
   //   | { attribute_instance } input_declaration
1114
   //   | { attribute_instance } output_declaration
1115
   //   | { attribute_instance } ref_declaration
1116
   //   | { attribute_instance } interface_port_declaration
1117

1118
   BEGIN("port declaration");
862✔
1119

1120
   switch (peek()) {
431✔
1121
   case tINOUT: p_inout_declaration(mod); break;
1✔
1122
   case tINPUT: p_input_declaration(mod); break;
233✔
1123
   case tOUTPUT: p_output_declaration(mod); break;
197✔
1124
   default: should_not_reach_here();
1125
   }
1126
}
431✔
1127

1128
static void p_net_port_header(v_port_kind_t *dir, vlog_node_t *dt)
92✔
1129
{
1130
   // [ port_direction ] net_port_type
1131

1132
   BEGIN("net port header");
184✔
1133

1134
   if (optional(tINPUT))
92✔
1135
      *dir = V_PORT_INPUT;
51✔
1136
   else if (optional(tINOUT))
41✔
1137
      *dir = V_PORT_INOUT;
×
1138
   else if (optional(tOUTPUT))
41✔
1139
      *dir = V_PORT_OUTPUT;
41✔
1140

1141
   vlog_net_kind_t kind;
92✔
1142
   p_net_port_type(&kind, dt);
92✔
1143
}
92✔
1144

1145
static void p_part_select_range(vlog_node_t ps)
279✔
1146
{
1147
   // constant_expression : constant_expression
1148
   //   | expression +: constant_expression
1149
   //   | expression -: constant_expression
1150

1151
   BEGIN("part select range");
558✔
1152

1153
   vlog_range_kind_t kind = V_RANGE_CONST;
279✔
1154
   switch (one_of(tCOLON, tINDEXPOS, tINDEXNEG)) {
279✔
1155
   case tINDEXPOS: kind = V_RANGE_POS; break;
21✔
1156
   case tINDEXNEG: kind = V_RANGE_NEG; break;
4✔
1157
   }
1158

1159
   vlog_set_subkind(ps, kind);
279✔
1160
   vlog_set_right(ps, p_constant_expression());
279✔
1161
}
279✔
1162

1163
static vlog_node_t p_hierarchical_identifier(ident_t id)
10✔
1164
{
1165
   // [ $root . ] { identifier constant_bit_select . } identifier
1166

1167
   EXTEND("hierarchical identifier");
20✔
1168

1169
   if (id == NULL)
10✔
1170
      id = p_identifier();
3✔
1171

1172
   vlog_node_t v = vlog_new(V_HIER_REF);
10✔
1173
   vlog_set_ident(v, id);
10✔
1174

1175
   consume(tDOT);
10✔
1176

1177
   ident_t suffix = NULL;
10✔
1178
   do {
11✔
1179
      suffix = ident_prefix(suffix, p_identifier(), '.');
11✔
1180
      vlog_set_ident2(v, suffix);
11✔
1181
   } while (optional(tDOT));
11✔
1182

1183
   vlog_set_loc(v, CURRENT_LOC);
10✔
1184
   vlog_symtab_lookup(symtab, v);
10✔
1185
   return v;
10✔
1186
}
1187

1188
static vlog_node_t p_select(ident_t id)
34,948✔
1189
{
1190
   // [ { . member_identifier bit_select } . member_identifier ]
1191
   //    { [ expression ] } [ [ part_select_range ] ]
1192

1193
   EXTEND("select");
69,896✔
1194

1195
   vlog_node_t d = vlog_symtab_query(symtab, id), prefix;
34,948✔
1196
   if (d != NULL && vlog_kind(d) == V_MOD_INST)
34,948✔
1197
      prefix = p_hierarchical_identifier(id);
2✔
1198
   else if (d == NULL && peek() == tDOT) {
34,946✔
1199
      // Assume this is a hierarchical reference to a later instance
1200
      prefix = p_hierarchical_identifier(id);
5✔
1201
   }
1202
   else {
1203
      prefix = vlog_new(V_REF);
34,941✔
1204
      vlog_set_ident(prefix, id);
34,941✔
1205
      vlog_set_loc(prefix, CURRENT_LOC);
34,941✔
1206

1207
      vlog_symtab_lookup(symtab, prefix);
34,941✔
1208

1209
      while (optional(tDOT)) {
35,030✔
1210
         vlog_node_t ref = vlog_new(V_MEMBER_REF);
89✔
1211
         vlog_set_ident(ref, p_identifier());
89✔
1212
         vlog_set_value(ref, prefix);
89✔
1213
         vlog_set_loc(ref, CURRENT_LOC);
89✔
1214

1215
         vlog_symtab_lookup(symtab, ref);
89✔
1216

1217
         prefix = ref;
89✔
1218
      }
1219
   }
1220

1221
   if (optional(tLSQUARE)) {
34,948✔
1222
      do {
1,197✔
1223
         vlog_node_t expr = p_expression();
1,197✔
1224
         if (scan(tCOLON, tINDEXPOS, tINDEXNEG)) {
1,197✔
1225
            vlog_node_t ps = vlog_new(V_PART_SELECT);
279✔
1226
            vlog_set_left(ps, expr);
279✔
1227
            vlog_set_value(ps, prefix);
279✔
1228

1229
            p_part_select_range(ps);
279✔
1230

1231
            consume(tRSQUARE);
279✔
1232

1233
            vlog_set_loc(ps, CURRENT_LOC);
279✔
1234
            return ps;
279✔
1235
         }
1236

1237
         if (vlog_kind(prefix) == V_BIT_SELECT)
918✔
1238
            vlog_add_param(prefix, expr);
84✔
1239
         else {
1240
            vlog_node_t bs = vlog_new(V_BIT_SELECT);
834✔
1241
            vlog_set_loc(bs, CURRENT_LOC);
834✔
1242
            vlog_set_value(bs, prefix);
834✔
1243
            vlog_add_param(bs, expr);
834✔
1244

1245
            prefix = bs;
834✔
1246
         }
1247

1248
         consume(tRSQUARE);
918✔
1249
      } while (optional(tLSQUARE));
918✔
1250
   }
1251

1252
   return prefix;
1253
}
1254

1255
static void p_list_of_arguments(vlog_node_t call)
5,284✔
1256
{
1257
   // [ expression ] { , [ expression ] } { , . identifier ( [ expression ] ) }
1258
   //    | . identifier ( [ expression ] ) { , . identifier ( [ expression ] ) }
1259

1260
   BEGIN("list of arguments");
10,568✔
1261

1262
   if (peek() == tRPAREN)
5,284✔
1263
      return;
7✔
1264

1265
   do {
10,373✔
1266
      if (peek() == tCOMMA) {
10,373✔
1267
         vlog_node_t v = vlog_new(V_EMPTY);
264✔
1268
         vlog_set_loc(v, &state.last_loc);
264✔
1269
         vlog_add_param(call, v);
264✔
1270
      }
1271
      else
1272
         vlog_add_param(call, p_expression());
10,109✔
1273
   } while (optional(tCOMMA));
10,373✔
1274
}
1275

1276
static vlog_node_t p_system_tf_call(vlog_kind_t kind)
8,096✔
1277
{
1278
   // system_tf_identifier [ ( list_of_arguments ) ]
1279

1280
   BEGIN("system task or function call");
16,192✔
1281

1282
   vlog_node_t v = vlog_new(kind);
8,096✔
1283
   vlog_set_ident(v, p_system_tf_identifier());
8,096✔
1284

1285
   if (optional(tLPAREN)) {
8,096✔
1286
      p_list_of_arguments(v);
4,901✔
1287
      consume(tRPAREN);
4,901✔
1288
   }
1289

1290
   vlog_set_loc(v, CURRENT_LOC);
8,096✔
1291
   return v;
8,096✔
1292
}
1293

1294
static vlog_node_t p_tf_call(vlog_kind_t kind)
387✔
1295
{
1296
   // ps_or_hierarchical_tf_identifier { attribute_instance }
1297
   //    [ ( list_of_arguments ) ]
1298

1299
   BEGIN("task or function call");
774✔
1300

1301
   vlog_node_t v = vlog_new(kind);
387✔
1302
   vlog_set_ident(v, p_identifier());
387✔
1303

1304
   optional_attributes();
387✔
1305

1306
   if (optional(tLPAREN)) {
387✔
1307
      p_list_of_arguments(v);
380✔
1308
      consume(tRPAREN);
380✔
1309
   }
1310

1311
   vlog_set_loc(v, CURRENT_LOC);
387✔
1312
   vlog_symtab_lookup(symtab, v);
387✔
1313
   return v;
387✔
1314
}
1315

1316
static vlog_node_t p_subroutine_call(vlog_kind_t kind)
8,483✔
1317
{
1318
   // tf_call | system_tf_call | method_call | [ std:: ] randomize_call
1319

1320
   BEGIN("subroutine call");
16,966✔
1321

1322
   if (peek() == tSYSTASK)
8,483✔
1323
      return p_system_tf_call(kind);
8,096✔
1324
   else
1325
      return p_tf_call(kind);
387✔
1326
}
1327

1328
static vlog_node_t p_mintypmax_expression(void)
42,760✔
1329
{
1330
   // expression | expression : expression : expression
1331

1332
   BEGIN("mintypmax expression");
85,520✔
1333

1334
   vlog_node_t e = p_expression();
42,760✔
1335

1336
   if (optional(tCOLON)) {
42,760✔
1337
      vlog_node_t mtm = vlog_new(V_MIN_TYP_MAX);
1✔
1338
      vlog_set_left(mtm, e);
1✔
1339
      vlog_set_value(mtm, p_expression());
1✔
1340

1341
      consume(tCOLON);
1✔
1342
      vlog_set_right(mtm, p_expression());
1✔
1343

1344
      return mtm;
1✔
1345
   }
1346

1347
   return e;
1348
}
1349

1350
static vlog_node_t p_concatenation(vlog_node_t head)
253✔
1351
{
1352
   // { expression { , expression } }
1353

1354
   BEGIN_WITH_HEAD("concatenation", head);
506✔
1355

1356
   if (head == NULL) {
253✔
1357
      consume(tLBRACE);
93✔
1358
      head = p_expression();
93✔
1359
   }
1360

1361
   vlog_node_t v = vlog_new(V_CONCAT);
253✔
1362
   vlog_add_param(v, head);
253✔
1363

1364
   while (optional(tCOMMA))
559✔
1365
      vlog_add_param(v, p_expression());
306✔
1366

1367
   consume(tRBRACE);
253✔
1368

1369
   vlog_set_loc(v, CURRENT_LOC);
253✔
1370
   return v;
253✔
1371
}
1372

1373
static vlog_node_t p_multiple_concatenation(vlog_node_t head)
93✔
1374
{
1375
   // { expression concatenation }
1376

1377
   BEGIN_WITH_HEAD("multiple concatenation", head);
186✔
1378

1379
   vlog_node_t v = p_concatenation(NULL);
93✔
1380
   vlog_set_value(v, head);
93✔
1381

1382
   consume(tRBRACE);
93✔
1383

1384
   vlog_set_loc(v, CURRENT_LOC);
93✔
1385
   return v;
93✔
1386
}
1387

1388
static vlog_node_t p_package_identifier(void)
3✔
1389
{
1390
   // identifier
1391

1392
   BEGIN("package identifier");
6✔
1393

1394
   ident_t id = p_identifier();
3✔
1395

1396
   lib_t work = lib_work();
3✔
1397
   ident_t qual = ident_prefix(lib_name(work), id, '.');
3✔
1398
   object_t *obj = lib_get_generic(lib_work(), qual, NULL);
3✔
1399
   vlog_node_t v = vlog_from_object(obj);
3✔
1400
   if (v == NULL || vlog_kind(v) != V_PACKAGE) {
3✔
1401
      parse_error(&state.last_loc, "no package named '%pi' in working "
×
1402
                  "library", id);
1403
      return NULL;
×
1404
   }
1405

1406
   return v;
1407
}
1408

1409
static vlog_node_t p_package_scope(void)
×
1410
{
1411
   // package_identifier :: | $unit ::
1412

1413
   BEGIN("package scope");
×
1414

1415
   switch (peek()) {
×
1416
   case tID:
×
1417
      {
1418
         vlog_node_t v = p_package_identifier();
×
1419
         consume(tSCOPE);
×
1420
         return v;
×
1421
      }
1422
   default:
×
1423
      one_of(tID);
×
1424
      return NULL;
×
1425
   }
1426
}
1427

1428
static vlog_node_t p_primary(void)
106,871✔
1429
{
1430
   // primary_literal | empty_queue
1431
   // | [ class_qualifier | package_scope ] hierarchical_identifier select
1432
   // | concatenation [ [ range_expression ] ]
1433
   // | multiple_concatenation [ [ range_expression ] ]
1434
   // | function_subroutine_call
1435
   // | let_expression | ( mintypmax_expression ) | cast
1436
   // | assignment_pattern_expression | streaming_concatenation
1437
   // | sequence_method_call | this | $ | null
1438

1439
   BEGIN("primary");
213,742✔
1440

1441
   switch (peek()) {
106,871✔
1442
   case tID:
24,694✔
1443
      switch (peek_nth(2)) {
24,694✔
1444
      case tLPAREN:
258✔
1445
      case tATTRBEGIN:
1446
         return p_subroutine_call(V_USER_FCALL);
258✔
1447
      case tSCOPE:
×
1448
         p_package_scope();
×
1449
      default:
24,436✔
1450
         return p_select(p_identifier());
24,436✔
1451
      }
1452
   case tSTRING:
36,636✔
1453
   case tNUMBER:
1454
   case tUNSNUM:
1455
   case tREAL:
1456
      return p_primary_literal();
36,636✔
1457
   case tSYSTASK:
2,886✔
1458
      return p_subroutine_call(V_SYS_FCALL);
2,886✔
1459
   case tLPAREN:
42,384✔
1460
      {
1461
         consume(tLPAREN);
42,384✔
1462
         vlog_node_t expr = p_mintypmax_expression();
42,384✔
1463
         consume(tRPAREN);
42,384✔
1464
         return expr;
42,384✔
1465
      }
1466
   case tLBRACE:
253✔
1467
      {
1468
         consume(tLBRACE);
253✔
1469

1470
         vlog_node_t head = p_expression();
253✔
1471
         if (peek() == tLBRACE)
253✔
1472
            return p_multiple_concatenation(head);
93✔
1473
         else
1474
            return p_concatenation(head);
160✔
1475
      }
1476
   case tNULL:
18✔
1477
      {
1478
         consume(tNULL);
18✔
1479

1480
         vlog_node_t v = vlog_new(V_NULL);
18✔
1481
         vlog_set_loc(v, CURRENT_LOC);
18✔
1482
         return v;
18✔
1483
      }
1484

1485
   default:
×
1486
      one_of(tID, tSTRING, tNUMBER, tUNSNUM, tREAL, tSYSTASK, tLPAREN,
×
1487
             tLBRACE, tNULL);
1488
      return p_select(error_marker());
×
1489
   }
1490
}
1491

1492
static vlog_binary_t p_binary_operator(void)
28,040✔
1493
{
1494
   // + | - | * | / | % | == | != | === | !== | ==? | !=? | && | ||
1495
   //  | ** | < | <= | > | >= | & | | | ^ | ^~ | ~^ | >> | <<
1496
   //  | >>> | <<< | -> | <->
1497

1498
   BEGIN("binary operator");
56,080✔
1499

1500
   switch (one_of(tBAR, tPLUS, tAMP, tCASEEQ, tCASENEQ, tLOGOR,
28,040✔
1501
                  tLOGEQ, tLOGNEQ, tDBLAMP, tSHIFTLL, tSHIFTRL,
1502
                  tSHIFTLA, tSHIFTRA, tLT, tGT, tLE, tGE, tMINUS,
1503
                  tTIMES, tOVER, tPERCENT, tPOWER, tCARET, tTILDECARET,
1504
                  tTILDEAMP)) {
1505
   case tBAR:        return V_BINARY_OR;
1506
   case tAMP:        return V_BINARY_AND;
1,252✔
1507
   case tCASEEQ:     return V_BINARY_CASE_EQ;
1,531✔
1508
   case tCASENEQ:    return V_BINARY_CASE_NEQ;
2,889✔
1509
   case tLOGEQ:      return V_BINARY_LOG_EQ;
1,740✔
1510
   case tLOGNEQ:     return V_BINARY_LOG_NEQ;
1,668✔
1511
   case tLOGOR:      return V_BINARY_LOG_OR;
1,742✔
1512
   case tDBLAMP:     return V_BINARY_LOG_AND;
1,514✔
1513
   case tSHIFTLL:    return V_BINARY_SHIFT_LL;
42✔
1514
   case tSHIFTRL:    return V_BINARY_SHIFT_RL;
32✔
1515
   case tSHIFTLA:    return V_BINARY_SHIFT_LA;
10✔
1516
   case tSHIFTRA:    return V_BINARY_SHIFT_RA;
27✔
1517
   case tLT:         return V_BINARY_LT;
1,348✔
1518
   case tGT:         return V_BINARY_GT;
1,401✔
1519
   case tLE:         return V_BINARY_LEQ;
1,392✔
1520
   case tGE:         return V_BINARY_GEQ;
1,428✔
1521
   case tMINUS:      return V_BINARY_MINUS;
1,665✔
1522
   case tTIMES:      return V_BINARY_TIMES;
1,345✔
1523
   case tOVER:       return V_BINARY_DIVIDE;
1,316✔
1524
   case tPERCENT:    return V_BINARY_MOD;
1,314✔
1525
   case tPOWER:      return V_BINARY_EXP;
17✔
1526
   case tCARET:      return V_BINARY_XOR;
1,211✔
1527
   case tTILDECARET: return V_BINARY_XNOR;
6✔
1528
   case tTILDEAMP:   return V_BINARY_NAND;
×
1529
   case tPLUS:
1,609✔
1530
   default:          return V_BINARY_PLUS;
1,609✔
1531
   }
1532
}
1533

1534
static vlog_unary_t p_unary_operator(void)
9,162✔
1535
{
1536
   // + | - | ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~
1537

1538
   BEGIN("unary operator");
18,324✔
1539

1540
   switch (one_of(tMINUS, tPLUS, tTILDE, tBANG, tAMP, tBAR, tCARET,
9,162✔
1541
                  tTILDEAMP, tTILDEBAR, tTILDECARET)) {
1542
   case tMINUS:      return V_UNARY_NEG;
1543
   case tTILDE:      return V_UNARY_BITNEG;
1,242✔
1544
   case tBANG:       return V_UNARY_NOT;
1,329✔
1545
   case tAMP:        return V_UNARY_AND;
1,309✔
1546
   case tBAR:        return V_UNARY_OR;
1,233✔
1547
   case tCARET:      return V_UNARY_XOR;
1,177✔
1548
   case tTILDEAMP:   return V_UNARY_NAND;
5✔
1549
   case tTILDEBAR:   return V_UNARY_NOR;
4✔
1550
   case tTILDECARET: return V_UNARY_XNOR;
×
1551
   case tPLUS:
1,330✔
1552
   default:          return V_UNARY_IDENTITY;
1,330✔
1553
   }
1554
}
1555

1556
static vlog_incdec_t p_inc_or_dec_operator(void)
42✔
1557
{
1558
   // ++ | --
1559

1560
   BEGIN("inc or dec operator");
84✔
1561

1562
   switch (one_of(tPLUSPLUS, tMINUSMINUS)) {
42✔
1563
   case tMINUSMINUS: return V_INCDEC_MINUS;
1564
   case tPLUSPLUS:
41✔
1565
   default: return V_INCDEC_PLUS;
41✔
1566
   }
1567
}
1568

1569
static vlog_node_t p_inc_or_dec_expression(vlog_node_t head)
40✔
1570
{
1571
   // inc_or_dec_operator { attribute_instance } variable_lvalue
1572
   //   | variable_lvalue { attribute_instance } inc_or_dec_operator
1573

1574
   BEGIN_WITH_HEAD("inc or dec expression", head);
80✔
1575

1576
   vlog_node_t v = vlog_new(head ? V_POSTFIX : V_PREFIX);
46✔
1577
   vlog_set_subkind(v, p_inc_or_dec_operator());
40✔
1578
   vlog_set_target(v, head ?: p_variable_lvalue());
40✔
1579

1580
   vlog_set_loc(v, CURRENT_LOC);
40✔
1581
   return v;
40✔
1582
}
1583

1584
static vlog_node_t p_nonbinary_expression(void)
106,877✔
1585
{
1586
   // primary | unary_operator { attribute_instance } primary
1587
   //   | inc_or_dec_expression | ( operator_assignment )
1588
   //   | conditional_expression | inside_expression | tagged_union_expression
1589

1590
   switch (peek()) {
106,877✔
1591
   case tID:
97,709✔
1592
   case tSTRING:
1593
   case tNUMBER:
1594
   case tUNSNUM:
1595
   case tREAL:
1596
   case tSYSTASK:
1597
   case tLPAREN:
1598
   case tLBRACE:
1599
   case tNULL:
1600
      return p_primary();
97,709✔
1601
   case tMINUS:
9,162✔
1602
   case tPLUS:
1603
   case tTILDE:
1604
   case tBANG:
1605
   case tAMP:
1606
   case tBAR:
1607
   case tCARET:
1608
   case tTILDEAMP:
1609
   case tTILDEBAR:
1610
   case tTILDECARET:
1611
      {
1612
         vlog_node_t v = vlog_new(V_UNARY);
9,162✔
1613
         vlog_set_subkind(v, p_unary_operator());
9,162✔
1614

1615
         optional_attributes();
9,162✔
1616

1617
         vlog_set_value(v, p_primary());
9,162✔
1618
         vlog_set_loc(v, CURRENT_LOC);
9,162✔
1619
         return v;
9,162✔
1620
      }
1621
   case tPLUSPLUS:
5✔
1622
   case tMINUSMINUS:
1623
      return p_inc_or_dec_expression(NULL);
5✔
1624
   default:
1✔
1625
      one_of(tID, tSTRING, tNUMBER, tUNSNUM, tREAL, tSYSTASK, tLPAREN,
1✔
1626
             tLBRACE, tNULL, tMINUS, tTILDE, tBANG, tAMP, tBAR, tCARET,
1627
             tTILDEAMP, tTILDEBAR, tPLUSPLUS, tTILDECARET, tMINUSMINUS);
1628
      return p_select(error_marker());
1✔
1629
   }
1630
}
1631

1632
static vlog_node_t p_conditional_expression(vlog_node_t head)
1,498✔
1633
{
1634
   // cond_predicate ? { attribute_instance } expression : expression
1635

1636
   BEGIN_WITH_HEAD("conditional expression", head);
2,996✔
1637

1638
   vlog_node_t v = vlog_new(V_COND_EXPR);
1,498✔
1639
   vlog_set_value(v, head);
1,498✔
1640

1641
   consume(tQUESTION);
1,498✔
1642

1643
   optional_attributes();
1,498✔
1644

1645
   vlog_set_left(v, p_expression());
1,498✔
1646

1647
   consume(tCOLON);
1,498✔
1648

1649
   vlog_set_right(v, p_expression());
1,498✔
1650

1651
   vlog_set_loc(v, CURRENT_LOC);
1,498✔
1652
   return v;
1,498✔
1653
}
1654

1655
static bool peek_binary_operator(int *prec)
137,825✔
1656
{
1657
   // See LRM 1800-2017 section 11.3.2 for operator precedence table
1658

1659
   switch (peek()) {
137,825✔
1660
   case tPOWER:      *prec = 12; return true;
21✔
1661
   case tTIMES:
3,987✔
1662
   case tOVER:
1663
   case tPERCENT:    *prec = 11; return true;
3,987✔
1664
   case tPLUS:
3,314✔
1665
   case tMINUS:      *prec = 10; return true;
3,314✔
1666
   case tSHIFTLL:
113✔
1667
   case tSHIFTRL:
1668
   case tSHIFTLA:
1669
   case tSHIFTRA:    *prec = 9;  return true;
113✔
1670
   case tLT:
5,597✔
1671
   case tGT:
1672
   case tLE:
1673
   case tGE:         *prec = 8;  return true;
5,597✔
1674
   case tCASEEQ:
8,496✔
1675
   case tCASENEQ:
1676
   case tLOGEQ:
1677
   case tLOGNEQ:     *prec = 7;  return true;
8,496✔
1678
   case tAMP:        *prec = 6;  return true;
1,254✔
1679
   case tTILDECARET:
1,217✔
1680
   case tCARET:      *prec = 5;  return true;
1,217✔
1681
   case tBAR:        *prec = 4;  return true;
1,542✔
1682
   case tDBLAMP:     *prec = 3;  return true;
1,802✔
1683
   case tLOGOR:      *prec = 2;  return true;
2,803✔
1684
   case tQUESTION:   *prec = 1;  return true;
1,508✔
1685
   default:
1686
      return false;
1687
   }
1688
}
1689

1690
static vlog_node_t p_binary_expression(vlog_node_t lhs, int min_prec)
79,542✔
1691
{
1692
   // Precedence climbing method, see
1693
   //    https://en.wikipedia.org/wiki/Operator-precedence_parser
1694

1695
   int prec1;
79,542✔
1696
   while (peek_binary_operator(&prec1) && prec1 >= min_prec) {
109,080✔
1697
      if (peek() == tQUESTION)
29,538✔
1698
         lhs = p_conditional_expression(lhs);
1,498✔
1699
      else {
1700
         vlog_node_t v = vlog_new(V_BINARY);
28,040✔
1701
         vlog_set_subkind(v, p_binary_operator());
28,040✔
1702
         vlog_set_left(v, lhs);
28,040✔
1703

1704
         optional_attributes();
28,040✔
1705

1706
         vlog_node_t rhs = p_nonbinary_expression();
28,040✔
1707

1708
         int prec2;
28,040✔
1709
         while (peek_binary_operator(&prec2) && prec2 > prec1)
28,745✔
1710
            rhs = p_binary_expression(rhs, prec1 + (prec2 > prec1));
705✔
1711

1712
         vlog_set_right(v, rhs);
28,040✔
1713
         vlog_set_loc(v, CURRENT_LOC);
28,040✔
1714
         lhs = v;
28,040✔
1715
      }
1716
   }
1717

1718
   return lhs;
79,542✔
1719
}
1720

1721
static vlog_node_t p_expression(void)
78,837✔
1722
{
1723
   // primary | unary_operator { attribute_instance } primary
1724
   //   | inc_or_dec_expression | ( operator_assignment )
1725
   //   | expression binary_operator { attribute_instance } expression
1726
   //   | conditional_expression | inside_expression | tagged_union_expression
1727

1728
   BEGIN("expression");
157,674✔
1729

1730
   vlog_node_t head = p_nonbinary_expression();
78,837✔
1731
   return p_binary_expression(head, 0);
78,837✔
1732
}
1733

1734
static void p_event_expression(vlog_node_t ctrl)
257✔
1735
{
1736
   // [ edge_identifier ] expression [ iff expression ]
1737
   //   | sequence_instance [ iff expression ]
1738
   //   | event_expression or event_expression
1739
   //   | event_expression , event_expression
1740
   //   | ( event_expression )
1741

1742
   BEGIN("event expression");
514✔
1743

1744
   do {
291✔
1745
      if (optional(tLPAREN)) {
291✔
1746
         p_event_expression(ctrl);
1✔
1747
         consume(tRPAREN);
1✔
1748
      }
1749
      else {
1750
         vlog_node_t v = vlog_new(V_EVENT);
290✔
1751

1752
         if (optional(tPOSEDGE))
290✔
1753
            vlog_set_subkind(v, V_EVENT_POSEDGE);
97✔
1754
         else if (optional(tNEGEDGE))
193✔
1755
            vlog_set_subkind(v, V_EVENT_NEGEDGE);
44✔
1756
         else
1757
            vlog_set_subkind(v, V_EVENT_LEVEL);
149✔
1758

1759
         vlog_set_value(v, p_expression());
290✔
1760
         vlog_set_loc(v, CURRENT_LOC);
290✔
1761

1762
         vlog_add_param(ctrl, v);
290✔
1763
      }
1764
   } while (optional(tOR) || optional(tCOMMA));
291✔
1765
}
257✔
1766

1767
static vlog_node_t p_cond_predicate(void)
1,825✔
1768
{
1769
   // expression_or_cond_pattern { &&& expression_or_cond_pattern }
1770

1771
   BEGIN("cond predicate");
3,650✔
1772

1773
   return p_expression();
1,825✔
1774
}
1775

1776
static vlog_node_t p_event_control(void)
331✔
1777
{
1778
   // @ hierarchical_event_identifier | @ ( event_expression )
1779
   //    | @* | @ (*) | @ ps_or_hierarchical_sequence_identifier
1780

1781
   BEGIN("event control");
662✔
1782

1783
   consume(tAT);
331✔
1784

1785
   vlog_node_t v = vlog_new(V_EVENT_CONTROL);
331✔
1786

1787
   switch (one_of(tLPAREN, tTIMES, tPARENSTAR)) {
331✔
1788
   case tLPAREN:
257✔
1789
      if (peek() == tATTREND)
257✔
1790
         consume(tATTREND);   // Lexing ambiguity
1✔
1791
      else {
1792
         p_event_expression(v);
256✔
1793
         consume(tRPAREN);
256✔
1794
      }
1795
      break;
1796
   case tTIMES:
1797
   case tPARENSTAR:
1798
      break;
1799
   }
1800

1801
   vlog_set_loc(v, CURRENT_LOC);
331✔
1802
   return v;
331✔
1803
}
1804

1805
static vlog_node_t p_delay_value(void)
4,476✔
1806
{
1807
   // unsigned_number | real_number | ps_identifier | time_literal | 1step
1808

1809
   BEGIN("delay value");
8,952✔
1810

1811
   switch (peek()) {
4,476✔
1812
   case tREAL:
5✔
1813
      return p_real_number();
5✔
1814
   case tID:
1✔
1815
      {
1816
         vlog_node_t v = vlog_new(V_REF);
1✔
1817
         vlog_set_ident(v, p_identifier());
1✔
1818
         vlog_set_loc(v, CURRENT_LOC);
1✔
1819

1820
         vlog_symtab_lookup(symtab, v);
1✔
1821
         return v;
1✔
1822
      }
1823
   case tUNSNUM:
4,470✔
1824
   default:
1825
      return p_unsigned_number();
4,470✔
1826
   }
1827
}
1828

1829
static vlog_node_t p_delay_control(void)
4,475✔
1830
{
1831
   // # delay_value | # ( mintypmax_expression )
1832

1833
   BEGIN("delay control");
8,950✔
1834

1835
   consume(tHASH);
4,475✔
1836

1837
   vlog_node_t v = vlog_new(V_DELAY_CONTROL);
4,475✔
1838

1839
   if (peek() != tLPAREN)
4,475✔
1840
      vlog_set_value(v, p_delay_value());
4,471✔
1841
   else
1842
      vlog_set_value(v, p_mintypmax_expression());
4✔
1843

1844
   vlog_set_loc(v, CURRENT_LOC);
4,475✔
1845
   return v;
4,475✔
1846
}
1847

1848
static void p_delay3(void)
7✔
1849
{
1850
   // # delay_value | # ( mintypmax_expression [ , mintypmax_expression
1851
   //   [ , mintypmax_expression ] ] )
1852

1853
   BEGIN("delay3");
14✔
1854

1855
   consume(tHASH);
7✔
1856

1857
   if (peek() != tLPAREN)
7✔
1858
      p_delay_value();
3✔
1859
   else {
1860
      consume(tLPAREN);
4✔
1861

1862
      int expr_cnt = 0;
4✔
1863
      do {
12✔
1864
         (void)p_mintypmax_expression();
12✔
1865
         expr_cnt++;
12✔
1866
      } while (optional(tCOMMA) && (expr_cnt < 3));
12✔
1867

1868
      consume(tRPAREN);
4✔
1869
   }
1870
}
7✔
1871

1872
static void p_delay2(void)
2✔
1873
{
1874
   // # delay_value | # ( mintypmax_expression [ , mintypmax_expression ] )
1875

1876
   BEGIN("delay2");
4✔
1877

1878
   consume(tHASH);
2✔
1879

1880
   if (peek() != tLPAREN)
2✔
1881
      p_delay_value();
1✔
1882
   else {
1883
      consume(tLPAREN);
1✔
1884

1885
      (void)p_mintypmax_expression();
1✔
1886

1887
      if (optional(tCOMMA))
1✔
1888
         (void)p_mintypmax_expression();
1✔
1889

1890
      consume(tRPAREN);
1✔
1891
   }
1892
}
2✔
1893

1894
static vlog_node_t p_delay_or_event_control(void)
50✔
1895
{
1896
   // delay_control | event_control | repeat ( expression ) event_control
1897

1898
   BEGIN("delay or event control");
100✔
1899

1900
   return p_delay_control();
50✔
1901
}
1902

1903
static vlog_node_t p_variable_lvalue(void)
9,968✔
1904
{
1905
   // [ implicit_class_handle . | package_scope ]
1906
   //      hierarchical_variable_identifier select
1907
   //   | { variable_lvalue { , variable_lvalue } }
1908
   //   | [ assignment_pattern_expression_type ]
1909
   //      assignment_pattern_variable_lvalue
1910
   //   | streaming_concatenation
1911

1912
   BEGIN("variable lvalue");
19,936✔
1913

1914
   if (optional(tLBRACE)) {
9,968✔
1915
      vlog_node_t v = vlog_new(V_CONCAT);
5✔
1916

1917
      do {
14✔
1918
         vlog_add_param(v, p_variable_lvalue());
14✔
1919
      } while (optional(tCOMMA));
14✔
1920

1921
      consume(tRBRACE);
5✔
1922

1923
      vlog_set_loc(v, CURRENT_LOC);
5✔
1924
      return v;
5✔
1925
   }
1926
   else {
1927
      ident_t id = p_identifier();
9,963✔
1928
      vlog_node_t v = p_select(id);
9,963✔
1929

1930
      vlog_set_loc(v, CURRENT_LOC);
9,963✔
1931
      return v;
9,963✔
1932
   }
1933
}
1934

1935
static vlog_node_t p_net_lvalue(void)
559✔
1936
{
1937
   // ps_or_hierarchical_net_identifier constant_select
1938
   //   | { net_lvalue { , net_lvalue } }
1939
   //   | [ assignment_pattern_expression_type ] assignment_pattern_net_lvalue
1940

1941
   BEGIN("net lvalue");
1,118✔
1942

1943
   if (optional(tLBRACE)) {
559✔
1944
      vlog_node_t v = vlog_new(V_CONCAT);
11✔
1945

1946
      do {
22✔
1947
         vlog_add_param(v, p_net_lvalue());
22✔
1948
      } while (optional(tCOMMA));
22✔
1949

1950
      consume(tRBRACE);
11✔
1951

1952
      vlog_set_loc(v, CURRENT_LOC);
11✔
1953
      return v;
11✔
1954
   }
1955
   else {
1956
      ident_t id = p_identifier();
548✔
1957
      vlog_node_t v = p_constant_select(id);
548✔
1958

1959
      vlog_set_loc(v, CURRENT_LOC);
548✔
1960
      return v;
548✔
1961
   }
1962
}
1963

1964
static vlog_node_t p_class_new(vlog_node_t dt)
8✔
1965
{
1966
   // [ class_scope ] new [ ( list_of_arguments ) ]
1967
   //    | new expression
1968

1969
   BEGIN("class new");
16✔
1970

1971
   consume(tNEW);
8✔
1972

1973
   if (dt == NULL || vlog_kind(dt) != V_CLASS_DECL) {
8✔
1974
      error_at(&state.last_loc, "new class expression must have class type");
1✔
1975
      dt = NULL;
1✔
1976
   }
1977

1978
   vlog_node_t v = vlog_new(V_CLASS_NEW);
8✔
1979
   vlog_set_type(v, dt);
8✔
1980

1981
   if (optional(tLPAREN)) {
8✔
1982
      p_list_of_arguments(v);
2✔
1983
      consume(tRPAREN);
2✔
1984
   }
1985

1986
   vlog_set_loc(v, CURRENT_LOC);
8✔
1987
   return v;
8✔
1988
}
1989

1990
static vlog_assign_t p_assignment_operator(void)
157✔
1991
{
1992
   // = | += | -= | *= | /= | %= | &= | |= | ^= | <<= | >>= | <<<= | >>>=
1993

1994
   BEGIN("assignment operator");
314✔
1995

1996
   switch (one_of(tEQ, tPLUSEQ, tMINUSEQ, tTIMESEQ, tDIVEQ, tPERCENTEQ, tAMPEQ,
157✔
1997
                  tBAREQ, tCARETEQ, tLSLEQ, tLSREQ, tASLEQ, tASREQ)) {
1998
   case tPLUSEQ:    return V_ASSIGN_PLUS;
1999
   case tMINUSEQ:   return V_ASSIGN_MINUS;
2000
   case tTIMESEQ:   return V_ASSIGN_TIMES;
2001
   case tDIVEQ:     return V_ASSIGN_DIVIDE;
2002
   case tPERCENTEQ: return V_ASSIGN_MOD;
2003
   case tAMPEQ:     return V_ASSIGN_AND;
2004
   case tBAREQ:     return V_ASSIGN_OR;
2005
   case tCARETEQ:   return V_ASSIGN_XOR;
2006
   case tLSLEQ:     return V_ASSIGN_SHIFT_LL;
2007
   case tLSREQ:     return V_ASSIGN_SHIFT_RL;
2008
   case tASLEQ:     return V_ASSIGN_SHIFT_LA;
2009
   case tASREQ:     return V_ASSIGN_SHIFT_RA;
2010
   default:         return V_ASSIGN_EQUALS;
2011
   }
2012
}
2013

2014
static vlog_node_t p_operator_assignment(vlog_node_t lhs)
157✔
2015
{
2016
   // variable_lvalue assignment_operator expression
2017

2018
   BEGIN_WITH_HEAD("operator assignment", lhs);
314✔
2019

2020
   vlog_node_t v = vlog_new(V_OP_ASSIGN);
157✔
2021
   vlog_set_subkind(v, p_assignment_operator());
157✔
2022
   vlog_set_target(v, lhs);
157✔
2023

2024
   vlog_set_value(v, p_expression());
157✔
2025

2026
   vlog_set_loc(v, CURRENT_LOC);
157✔
2027
   return v;
157✔
2028
}
2029

2030
static vlog_node_t p_blocking_assignment(vlog_node_t lhs)
9,467✔
2031
{
2032
   // variable_lvalue = delay_or_event_control expression
2033
   //   | nonrange_variable_lvalue = dynamic_array_new
2034
   //   | [ implicit_class_handle . | class_scope | package_scope ]
2035
   //         hierarchical_variable_identifier select = class_new
2036
   //   | operator_assignment
2037

2038
   BEGIN_WITH_HEAD("blocking assignment", lhs);
18,934✔
2039

2040
   switch (peek()) {
9,467✔
2041
   case tPLUSEQ:
102✔
2042
   case tMINUSEQ:
2043
   case tTIMESEQ:
2044
   case tDIVEQ:
2045
   case tPERCENTEQ:
2046
   case tAMPEQ:
2047
   case tBAREQ:
2048
   case tCARETEQ:
2049
   case tLSLEQ:
2050
   case tLSREQ:
2051
   case tASLEQ:
2052
   case tASREQ:
2053
      return p_operator_assignment(lhs);
102✔
2054
   }
2055

2056
   consume(tEQ);
9,365✔
2057

2058
   vlog_node_t v = vlog_new(V_BASSIGN);
9,365✔
2059
   vlog_set_target(v, lhs);
9,365✔
2060

2061
   if (peek() == tNEW)
9,365✔
2062
      vlog_set_value(v, p_class_new(vlog_get_type(lhs)));
8✔
2063
   else {
2064
      if (scan(tHASH, tAT))
9,357✔
2065
         vlog_set_delay(v, p_delay_or_event_control());
33✔
2066

2067
      vlog_set_value(v, p_expression());
9,357✔
2068
   }
2069

2070
   vlog_set_loc(v, CURRENT_LOC);
9,365✔
2071
   return v;
9,365✔
2072
}
2073

2074
static vlog_node_t p_nonblocking_assignment(vlog_node_t lhs)
312✔
2075
{
2076
   // variable_lvalue <= [ delay_or_event_control ] expression
2077

2078
   BEGIN_WITH_HEAD("non-blocking assignment", lhs);
624✔
2079

2080
   consume(tLE);
312✔
2081

2082
   vlog_node_t v = vlog_new(V_NBASSIGN);
312✔
2083
   vlog_set_target(v, lhs);
312✔
2084

2085
   if (scan(tHASH, tAT))
312✔
2086
      vlog_set_delay(v, p_delay_or_event_control());
17✔
2087

2088
   vlog_set_value(v, p_expression());
312✔
2089

2090
   vlog_set_loc(v, CURRENT_LOC);
312✔
2091
   return v;
312✔
2092
}
2093

2094
static vlog_node_t p_procedural_timing_control(void)
4,744✔
2095
{
2096
   // delay_control | event_control | cycle_delay
2097

2098
   BEGIN("procedural timing control");
9,488✔
2099

2100
   switch (peek()) {
4,744✔
2101
   case tAT:
331✔
2102
      return p_event_control();
331✔
2103
   case tHASH:
4,413✔
2104
      return p_delay_control();
4,413✔
2105
   default:
×
2106
      should_not_reach_here();
2107
   }
2108
}
2109

2110
static vlog_node_t p_procedural_timing_control_statement(void)
4,744✔
2111
{
2112
   // procedural_timing_control statement_or_null
2113

2114
   BEGIN("procedural timing control statement");
9,488✔
2115

2116
   vlog_node_t v = vlog_new(V_TIMING);
4,744✔
2117
   vlog_set_value(v, p_procedural_timing_control());
4,744✔
2118

2119
   vlog_node_t s = p_statement_or_null();
4,744✔
2120
   if (s != NULL)
4,744✔
2121
      vlog_add_stmt(v, s);
560✔
2122

2123
   vlog_set_loc(v, CURRENT_LOC);
4,744✔
2124
   return v;
4,744✔
2125
}
2126

2127
static vlog_node_t p_seq_block(ident_t id)
1,976✔
2128
{
2129
   // begin [ : block_identifier ] { block_item_declaration }
2130
   //   { statement_or_null } end [ : block_identifier ]
2131

2132
   BEGIN("sequential block");
3,952✔
2133

2134
   consume(tBEGIN);
1,976✔
2135

2136
   vlog_node_t v = vlog_new(V_BLOCK);
1,976✔
2137
   vlog_set_ident(v, id);
1,976✔
2138
   vlog_set_loc(v, CURRENT_LOC);
1,976✔
2139

2140
   vlog_symtab_push(symtab, v);
1,976✔
2141

2142
   if (optional(tCOLON)) {
1,976✔
2143
      ident_t name = p_identifier();
14✔
2144
      if (vlog_has_ident(v))
14✔
2145
         parse_error(&state.last_loc, "cannot specify both a statement label "
1✔
2146
                     "and a block name");
2147
      else
2148
         vlog_set_ident(v, name);
13✔
2149
   }
2150

2151
   skip_over_attributes();
1,976✔
2152

2153
   while (scan_block_item_declaration()) {
1,992✔
2154
      p_block_item_declaration(v);
16✔
2155
      skip_over_attributes();
16✔
2156
   }
2157

2158
   while (not_at_token(tEND)) {
21,731✔
2159
      vlog_node_t s = p_statement_or_null();
19,755✔
2160
      if (s != NULL)
19,755✔
2161
         vlog_add_stmt(v, s);
19,754✔
2162
   }
2163

2164
   vlog_symtab_pop(symtab);
1,976✔
2165

2166
   consume(tEND);
1,976✔
2167

2168
   if (optional(tCOLON)) {
1,976✔
2169
      ident_t name = p_identifier();
6✔
2170
      if (!vlog_has_ident(v))
6✔
2171
         parse_error(&state.last_loc, "initial block does not have a label");
1✔
2172
      else if (name != vlog_ident(v))
5✔
2173
         parse_error(&state.last_loc, "'%s' does not match label '%s'",
1✔
2174
                     istr(name), istr(vlog_ident(v)));
2175
   }
2176

2177
   return v;
1,976✔
2178
}
2179

2180
static vlog_node_t p_par_block(ident_t id)
7✔
2181
{
2182
   // fork [ : block_identifier ] { block_item_declaration }
2183
   //   { statement_or_null } join_keyword [ : block_identifier ]
2184

2185
   BEGIN("parallel block");
14✔
2186

2187
   consume(tFORK);
7✔
2188

2189
   vlog_node_t v = vlog_new(V_FORK);
7✔
2190
   vlog_set_ident(v, id);
7✔
2191
   vlog_set_loc(v, CURRENT_LOC);
7✔
2192

2193
   vlog_symtab_push(symtab, v);
7✔
2194

2195
   if (optional(tCOLON)) {
7✔
2196
      ident_t name = p_identifier();
4✔
2197
      if (vlog_has_ident(v))
4✔
2198
         parse_error(&state.last_loc, "cannot specify both a statement label "
1✔
2199
                     "and a block name");
2200
      else
2201
         vlog_set_ident(v, name);
3✔
2202
   }
2203

2204
   skip_over_attributes();
7✔
2205

2206
   while (scan_block_item_declaration()) {
9✔
2207
      p_block_item_declaration(v);
2✔
2208
      skip_over_attributes();
2✔
2209
   }
2210

2211
   while (not_at_token(tJOIN)) {
14✔
2212
      vlog_node_t s = p_statement_or_null();
7✔
2213
      if (s != NULL)
7✔
2214
         vlog_add_stmt(v, s);
7✔
2215
   }
2216

2217
   vlog_symtab_pop(symtab);
7✔
2218

2219
   consume(tJOIN);
7✔
2220

2221
   if (optional(tCOLON)) {
7✔
2222
      ident_t name = p_identifier();
5✔
2223
      if (!vlog_has_ident(v))
5✔
2224
         parse_error(&state.last_loc, "fork block does not have a label");
1✔
2225
      else if (name != vlog_ident(v))
4✔
2226
         parse_error(&state.last_loc, "'%s' does not match label '%s'",
1✔
2227
                     istr(name), istr(vlog_ident(v)));
2228
   }
2229

2230
   return v;
7✔
2231
}
2232

2233
static vlog_node_t p_subroutine_call_statement(void)
5,339✔
2234
{
2235
   // subroutine_call ; | void ' ( function_subroutine_call ) ;
2236

2237
   BEGIN("subroutine call statement");
10,678✔
2238

2239
   vlog_node_t v;
5,339✔
2240
   switch (peek()) {
5,339✔
2241
   case tSYSTASK:
5,210✔
2242
      v = p_subroutine_call(V_SYS_TCALL);
5,210✔
2243
      break;
5,210✔
2244
   case tVOID:
2✔
2245
      {
2246
         consume(tVOID);
2✔
2247
         consume(tTICK);
2✔
2248
         consume(tLPAREN);
2✔
2249

2250
         const vlog_kind_t kind =
4✔
2251
            peek() == tSYSTASK ? V_SYS_FCALL : V_USER_FCALL;
2✔
2252

2253
         v = vlog_new(V_VOID_CALL);
2✔
2254
         vlog_set_value(v, p_subroutine_call(kind));
2✔
2255

2256
         consume(tRPAREN);
2✔
2257
      }
2258
      break;
2✔
2259
   case tID:
127✔
2260
   default:
2261
      v = p_subroutine_call(V_USER_TCALL);
127✔
2262
      break;
127✔
2263
   }
2264

2265
   consume(tSEMI);
5,339✔
2266

2267
   vlog_set_loc(v, CURRENT_LOC);
5,339✔
2268
   return v;
5,339✔
2269
}
2270

2271
static vlog_node_t p_conditional_statement(void)
1,788✔
2272
{
2273
   // [ unique_priority ] if ( cond_predicate ) statement_or_null
2274
   //     { else if ( cond_predicate ) statement_or_null }
2275
   //     [ else statement_or_null ]
2276

2277
   BEGIN("conditional statement");
3,576✔
2278

2279
   vlog_node_t v = vlog_new(V_IF);
1,788✔
2280

2281
   consume(tIF);
1,788✔
2282
   consume(tLPAREN);
1,788✔
2283

2284
   vlog_node_t c0 = vlog_new(V_COND);
1,788✔
2285
   vlog_set_value(c0, p_cond_predicate());
1,788✔
2286
   vlog_add_cond(v, c0);
1,788✔
2287

2288
   consume(tRPAREN);
1,788✔
2289

2290
   vlog_node_t s0 = p_statement_or_null();
1,788✔
2291
   if (s0 != NULL)
1,788✔
2292
      vlog_add_stmt(c0, s0);
1,777✔
2293

2294
   bool stop = false;
2295
   while (!stop && optional(tELSE)) {
2,159✔
2296
      vlog_node_t c = vlog_new(V_COND);
371✔
2297
      vlog_add_cond(v, c);
371✔
2298

2299
      if (optional(tIF)) {
371✔
2300
         consume(tLPAREN);
37✔
2301
         vlog_set_value(c, p_cond_predicate());
37✔
2302
         consume(tRPAREN);
37✔
2303
      }
2304
      else
2305
         stop = true;
2306

2307
      vlog_node_t s = p_statement_or_null();
371✔
2308
      if (s != NULL)
371✔
2309
         vlog_add_stmt(c, s);
370✔
2310
   }
2311

2312
   vlog_set_loc(v, CURRENT_LOC);
1,788✔
2313
   return v;
1,788✔
2314
}
2315

2316
static vlog_node_t p_variable_assignment(vlog_kind_t kind)
78✔
2317
{
2318
   // variable_lvalue = expression
2319

2320
   BEGIN("variable assignment");
156✔
2321

2322
   vlog_node_t v = vlog_new(kind);
78✔
2323
   vlog_set_target(v, p_variable_lvalue());
78✔
2324

2325
   consume(tEQ);
78✔
2326

2327
   vlog_set_value(v, p_expression());
78✔
2328

2329
   vlog_set_loc(v, CURRENT_LOC);
78✔
2330
   return v;
78✔
2331
}
2332

2333
static void p_list_of_variable_assignments(vlog_node_t parent)
76✔
2334
{
2335
   // variable_assignment { , variable_assignment }
2336

2337
   BEGIN("list of variable assignments");
152✔
2338

2339
   do {
76✔
2340
      vlog_node_t v = p_variable_assignment(V_BASSIGN);
76✔
2341
      vlog_add_stmt(parent, v);
76✔
2342
   } while (optional(tCOMMA));
76✔
2343
}
76✔
2344

2345
static void p_for_variable_declaration(vlog_node_t parent)
2✔
2346
{
2347
   // [ var ] data_type variable_identifier = expression
2348
   //   { , variable_identifier = expression }
2349

2350
   BEGIN("for variable declaration");
4✔
2351

2352
   optional(tVAR);
2✔
2353

2354
   vlog_node_t dt = p_data_type();
2✔
2355

2356
   do {
2✔
2357
      vlog_node_t v = vlog_new(V_VAR_DECL);
2✔
2358
      vlog_set_ident(v, p_identifier());
2✔
2359
      vlog_set_type(v, dt);
2✔
2360

2361
      consume(tEQ);
2✔
2362

2363
      vlog_set_value(v, p_expression());
2✔
2364

2365
      vlog_set_loc(v, CURRENT_LOC);
2✔
2366
      vlog_add_decl(parent, v);
2✔
2367

2368
      vlog_symtab_put(symtab, v);
2✔
2369
   } while (optional(tCOMMA));
2✔
2370
}
2✔
2371

2372
static vlog_node_t p_for_initialization(void)
78✔
2373
{
2374
   // list_of_variable_assignments
2375
   //   | for_variable_declaration { , for_variable_declaration }
2376

2377
   BEGIN("for initialization");
156✔
2378

2379
   vlog_node_t v = vlog_new(V_FOR_INIT);
78✔
2380

2381
   if (scan(tREG, tSTRUCT, tUNION, tENUM, tSVINT, tINTEGER, tSVREAL,
78✔
2382
            tSHORTREAL, tREALTIME, tLOGIC, tVAR)) {
2383
      do {
2✔
2384
         p_for_variable_declaration(v);
2✔
2385
      } while (optional(tCOMMA));
2✔
2386
   }
2387
   else
2388
      p_list_of_variable_assignments(v);
76✔
2389

2390
   vlog_set_loc(v, CURRENT_LOC);
78✔
2391
   return v;
78✔
2392
}
2393

2394
static vlog_node_t p_for_step(void)
78✔
2395
{
2396
   // operator_assignment | inc_or_dec_expression | function_subroutine_call
2397

2398
   BEGIN("for step");
156✔
2399

2400
   vlog_node_t v = vlog_new(V_FOR_STEP);
78✔
2401

2402
   switch (peek()) {
78✔
2403
   case tPLUSPLUS:
1✔
2404
   case tMINUSMINUS:
2405
      vlog_add_stmt(v, p_inc_or_dec_expression(NULL));
1✔
2406
      break;
1✔
2407
   default:
77✔
2408
      {
2409
         vlog_node_t head = p_variable_lvalue();
77✔
2410

2411
         switch (peek()) {
77✔
2412
         case tPLUSPLUS:
22✔
2413
         case tMINUSMINUS:
2414
            vlog_add_stmt(v, p_inc_or_dec_expression(head));
22✔
2415
            break;
22✔
2416
         default:
55✔
2417
            vlog_add_stmt(v, p_operator_assignment(head));
55✔
2418
            break;
55✔
2419
         }
2420
      }
2421
      break;
2422
   }
2423

2424
   vlog_set_loc(v, CURRENT_LOC);
78✔
2425
   return v;
78✔
2426
}
2427

2428
static vlog_node_t p_loop_statement(void)
118✔
2429
{
2430
   // forever statement_or_null
2431
   //   | repeat ( expression ) statement_or_null
2432
   //   | while ( expression ) statement_or_null
2433
   //   | for ( [ for_initialization ] ; [ expression ] ; [ for_step ] )
2434
   //       statement_or_null
2435
   //   | do statement_or_null while ( expression ) ;
2436
   //   | foreach ( ps_or_hierarchical_array_identifier [ loop_variables ] )
2437
   //       statement
2438

2439
   BEGIN("loop statement");
236✔
2440

2441
   switch (one_of(tFOREVER, tWHILE, tREPEAT, tDO, tFOR)) {
118✔
2442
   case tFOREVER:
13✔
2443
      {
2444
         vlog_node_t v = vlog_new(V_FOREVER);
13✔
2445

2446
         vlog_node_t s = p_statement_or_null();
13✔
2447
         if (s != NULL)
13✔
2448
            vlog_add_stmt(v, s);
13✔
2449

2450
         vlog_set_loc(v, CURRENT_LOC);
13✔
2451
         return v;
13✔
2452
      }
2453

2454
   case tWHILE:
6✔
2455
      {
2456
         vlog_node_t v = vlog_new(V_WHILE);
6✔
2457

2458
         consume(tLPAREN);
6✔
2459
         vlog_set_value(v, p_expression());
6✔
2460
         consume(tRPAREN);
6✔
2461

2462
         vlog_node_t s = p_statement_or_null();
6✔
2463
         if (s != NULL)
6✔
2464
            vlog_add_stmt(v, s);
4✔
2465

2466
         vlog_set_loc(v, CURRENT_LOC);
6✔
2467
         return v;
6✔
2468
      }
2469

2470
   case tREPEAT:
18✔
2471
      {
2472
         vlog_node_t v = vlog_new(V_REPEAT);
18✔
2473

2474
         consume(tLPAREN);
18✔
2475
         vlog_set_value(v, p_expression());
18✔
2476
         consume(tRPAREN);
18✔
2477

2478
         vlog_node_t s = p_statement_or_null();
18✔
2479
         if (s != NULL)
18✔
2480
            vlog_add_stmt(v, s);
18✔
2481

2482
         vlog_set_loc(v, CURRENT_LOC);
18✔
2483
         return v;
18✔
2484
      }
2485

2486
   case tDO:
2✔
2487
      {
2488
         vlog_node_t v = vlog_new(V_DO_WHILE);
2✔
2489

2490
         vlog_node_t s = p_statement_or_null();
2✔
2491
         if (s != NULL)
2✔
2492
            vlog_add_stmt(v, s);
2✔
2493

2494
         consume(tWHILE);
2✔
2495

2496
         consume(tLPAREN);
2✔
2497
         vlog_set_value(v, p_expression());
2✔
2498
         consume(tRPAREN);
2✔
2499
         consume(tSEMI);
2✔
2500

2501
         vlog_set_loc(v, CURRENT_LOC);
2✔
2502
         return v;
2✔
2503
      }
2504

2505
   case tFOR:
79✔
2506
      {
2507
         vlog_node_t v = vlog_new(V_FOR_LOOP);
79✔
2508

2509
         vlog_symtab_push(symtab, v);
79✔
2510

2511
         consume(tLPAREN);
79✔
2512

2513
         if (not_at_token(tSEMI))
79✔
2514
            vlog_set_left(v, p_for_initialization());
78✔
2515
         else
2516
            vlog_set_left(v, vlog_new(V_FOR_INIT));
1✔
2517

2518
         consume(tSEMI);
79✔
2519

2520
         if (not_at_token(tSEMI))
79✔
2521
            vlog_set_value(v, p_expression());
77✔
2522

2523
         consume(tSEMI);
79✔
2524

2525
         if (not_at_token(tRPAREN))
79✔
2526
            vlog_set_right(v, p_for_step());
78✔
2527
         else
2528
            vlog_set_right(v, vlog_new(V_FOR_STEP));
1✔
2529

2530
         consume(tRPAREN);
79✔
2531

2532
         vlog_node_t s = p_statement_or_null();
79✔
2533
         if (s != NULL)
79✔
2534
            vlog_add_stmt(v, s);
76✔
2535

2536
         vlog_symtab_pop(symtab);
79✔
2537

2538
         vlog_set_loc(v, CURRENT_LOC);
79✔
2539
         return v;
79✔
2540
      }
2541

2542
   default:
×
2543
      should_not_reach_here();
2544
   }
2545
}
2546

2547
static vlog_node_t p_wait_statement(void)
1✔
2548
{
2549
   // wait ( expression ) statement_or_null
2550
   //   | wait fork ;
2551
   //   | wait_order ( hierarchical_identifier { , hierarchical_identifier } )
2552
   //       action_block
2553

2554
   BEGIN("wait statement");
2✔
2555

2556
   consume(tWAIT);
1✔
2557

2558
   vlog_node_t v = vlog_new(V_WAIT);
1✔
2559

2560
   consume(tLPAREN);
1✔
2561

2562
   vlog_set_value(v, p_expression());
1✔
2563

2564
   consume(tRPAREN);
1✔
2565

2566
   vlog_node_t s = p_statement_or_null();
1✔
2567
   if (s != NULL)
1✔
2568
      vlog_add_stmt(v, s);
1✔
2569

2570
   vlog_set_loc(v, CURRENT_LOC);
1✔
2571
   return v;
1✔
2572
}
2573

2574
static vlog_node_t p_case_item(void)
196✔
2575
{
2576
   // case_item_expression { , case_item_expression } : statement_or_null
2577
   //   | default [ : ] statement_or_null
2578

2579
   BEGIN("case item");
392✔
2580

2581
   vlog_node_t v = vlog_new(V_CASE_ITEM);
196✔
2582

2583
   if (optional(tDEFAULT))
196✔
2584
      optional(tCOLON);
43✔
2585
   else {
2586
      do {
157✔
2587
         vlog_add_param(v, p_expression());
157✔
2588
      } while (optional(tCOMMA));
157✔
2589

2590
      consume(tCOLON);
153✔
2591
   }
2592

2593
   vlog_set_loc(v, CURRENT_LOC);
196✔
2594

2595
   vlog_node_t s = p_statement_or_null();
196✔
2596
   if (s != NULL)
196✔
2597
      vlog_add_stmt(v, s);
195✔
2598

2599
   return v;
196✔
2600
}
2601

2602
static vlog_node_t p_case_statement(void)
54✔
2603
{
2604
   // [ unique_priority ] case_keyword ( case_expression )
2605
   //        case_item { case_item } endcase
2606
   //   | [ unique_priority ] case_keyword ( case_expression ) matches
2607
   //        case_pattern_item { case_pattern_item } endcase
2608
   //   | [ unique_priority ] case ( case_expression ) inside case_inside_item
2609
   //        { case_inside_item } endcase
2610

2611
   BEGIN("case statement");
108✔
2612

2613
   vlog_case_kind_t kind = V_CASE_NORMAL;
54✔
2614
   switch (one_of(tCASE, tCASEX, tCASEZ)) {
54✔
2615
   case tCASEX: kind = V_CASE_X; break;
9✔
2616
   case tCASEZ: kind = V_CASE_Z; break;
12✔
2617
   }
2618

2619
   vlog_node_t v = vlog_new(V_CASE);
54✔
2620
   vlog_set_subkind(v, kind);
54✔
2621

2622
   consume(tLPAREN);
54✔
2623

2624
   vlog_set_value(v, p_expression());
54✔
2625

2626
   consume(tRPAREN);
54✔
2627

2628
   do {
196✔
2629
      vlog_add_stmt(v, p_case_item());
196✔
2630
   } while (not_at_token(tENDCASE));
196✔
2631

2632
   consume(tENDCASE);
54✔
2633

2634
   vlog_set_loc(v, CURRENT_LOC);
54✔
2635
   return v;
54✔
2636
}
2637

2638
static vlog_node_t p_event_trigger(void)
1✔
2639
{
2640
   // -> hierarchical_event_identifier ;
2641
   //   | ->> [ delay_or_event_control ] hierarchical_event_identifier ;
2642

2643
   BEGIN("event trigger");
2✔
2644

2645
   consume(tIFIMPL);
1✔
2646

2647
   vlog_node_t v = vlog_new(V_EVENT_TRIGGER);
1✔
2648
   vlog_set_ident(v, p_identifier());
1✔
2649

2650
   consume(tSEMI);
1✔
2651

2652
   vlog_set_loc(v, CURRENT_LOC);
1✔
2653
   return v;
1✔
2654
}
2655

2656
static vlog_node_t p_procedural_continuous_assignment(void)
4✔
2657
{
2658
   // assign variable_assignment | deassign variable_lvalue
2659
   //   | force variable_assignment | force net_assignment
2660
   //   | release variable_lvalue | release net_lvalue
2661

2662
   BEGIN("procedural continuous assignment");
8✔
2663

2664
   switch (one_of(tASSIGN, tDEASSIGN, tFORCE, tRELEASE)) {
4✔
2665
   case tASSIGN:
1✔
2666
   default:
2667
      return p_variable_assignment(V_ASSIGN);
1✔
2668
   case tDEASSIGN:
1✔
2669
      {
2670
         vlog_node_t v = vlog_new(V_DEASSIGN);
1✔
2671
         vlog_set_target(v, p_variable_lvalue());
1✔
2672
         vlog_set_loc(v, CURRENT_LOC);
1✔
2673
         return v;
1✔
2674
      }
2675
   case tFORCE:
1✔
2676
      return p_variable_assignment(V_FORCE);
1✔
2677
   case tRELEASE:
1✔
2678
      {
2679
         vlog_node_t v = vlog_new(V_RELEASE);
1✔
2680
         vlog_set_target(v, p_variable_lvalue());
1✔
2681
         vlog_set_loc(v, CURRENT_LOC);
1✔
2682
         return v;
1✔
2683
      }
2684
   }
2685
}
2686

2687
static vlog_node_t p_disable_statement(void)
1✔
2688
{
2689
   // disable hierarchical_task_identifier ;
2690
   //   | disable hierarchical_block_identifier ;
2691
   //   | disable fork ;
2692

2693
   BEGIN("disable statement");
2✔
2694

2695
   consume(tDISABLE);
1✔
2696

2697
   vlog_node_t v = vlog_new(V_DISABLE);
1✔
2698
   vlog_set_ident(v, p_identifier());
1✔
2699

2700
   consume(tSEMI);
1✔
2701

2702
   vlog_set_loc(v, CURRENT_LOC);
1✔
2703
   return v;
1✔
2704
}
2705

2706
static vlog_node_t p_jump_statement(void)
7✔
2707
{
2708
   // return [ expression ] ; | break ; | continue ;
2709

2710
   BEGIN("jump statement");
14✔
2711

2712
   switch (one_of(tRETURN)) {
7✔
2713
   case tRETURN:
7✔
2714
      {
2715
         vlog_node_t v = vlog_new(V_RETURN);
7✔
2716

2717
         vlog_node_t subr = vlog_symtab_subr(symtab);
7✔
2718
         if (subr == NULL)
7✔
2719
            parse_error(&state.last_loc, "return statement can only be used "
1✔
2720
                        "in a subroutine");
2721
         else
2722
            vlog_set_ref(v, subr);
6✔
2723

2724
         if (peek() != tSEMI)
7✔
2725
            vlog_set_value(v, p_expression());
5✔
2726

2727
         consume(tSEMI);
7✔
2728

2729
         vlog_set_loc(v, CURRENT_LOC);
7✔
2730
         return v;
14✔
2731
      }
2732
   default:
×
2733
      should_not_reach_here();
2734
   }
2735
}
2736

2737
static vlog_node_t p_statement_item(ident_t id)
23,833✔
2738
{
2739
   // blocking_assignment ; | nonblocking_assignment ;
2740
   //   | procedural_continuous_assignment ; | case_statement
2741
   //   | conditional_statement | inc_or_dec_expression ;
2742
   //   | subroutine_call_statement | disable_statement
2743
   //   | event_trigger | loop_statement | jump_statement
2744
   //   | par_block | procedural_timing_control_statement
2745
   //   | seq_block | wait_statement | procedural_assertion_statement
2746
   //   | clocking_drive ; | randsequence_statement | randcase_statement
2747
   //   | expect_property_statement
2748

2749
   BEGIN("statement item");
47,666✔
2750

2751
   switch (peek()) {
23,833✔
2752
   case tID:
9,913✔
2753
      switch (peek_nth(2)) {
9,913✔
2754
      case tLPAREN:
127✔
2755
      case tSEMI:
2756
      case tATTRBEGIN:
2757
         return p_subroutine_call_statement();
127✔
2758
      default:
9,786✔
2759
         {
2760
            vlog_node_t lhs = p_variable_lvalue(), v;
9,786✔
2761

2762
            switch (peek()) {
9,786✔
2763
            case tLE:
312✔
2764
               v = p_nonblocking_assignment(lhs);
312✔
2765
               break;
312✔
2766
            case tPLUSPLUS:
12✔
2767
            case tMINUSMINUS:
2768
               v = p_inc_or_dec_expression(lhs);
12✔
2769
               break;
12✔
2770
            default:
9,462✔
2771
               v = p_blocking_assignment(lhs);
9,462✔
2772
               break;
9,462✔
2773
            }
2774

2775
            consume(tSEMI);
9,786✔
2776
            return v;
9,786✔
2777
         }
2778
      }
2779
   case tLBRACE:
5✔
2780
      {
2781
         vlog_node_t lhs = p_variable_lvalue(), v;
5✔
2782

2783
         if (peek() == tLE)
5✔
2784
            v = p_nonblocking_assignment(lhs);
×
2785
         else
2786
            v = p_blocking_assignment(lhs);
5✔
2787

2788
         consume(tSEMI);
5✔
2789
         return v;
5✔
2790
      }
2791
   case tDISABLE:
1✔
2792
      return p_disable_statement();
1✔
2793
   case tAT:
4,744✔
2794
   case tHASH:
2795
      return p_procedural_timing_control_statement();
4,744✔
2796
   case tBEGIN:
1,976✔
2797
      return p_seq_block(id);
1,976✔
2798
   case tFORK:
7✔
2799
      return p_par_block(id);
7✔
2800
   case tSYSTASK:
5,212✔
2801
   case tVOID:
2802
      return p_subroutine_call_statement();
5,212✔
2803
   case tIF:
1,788✔
2804
      return p_conditional_statement();
1,788✔
2805
   case tFOREVER:
118✔
2806
   case tWHILE:
2807
   case tREPEAT:
2808
   case tDO:
2809
   case tFOR:
2810
      return p_loop_statement();
118✔
2811
   case tWAIT:
1✔
2812
      return p_wait_statement();
1✔
2813
   case tCASE:
54✔
2814
   case tCASEX:
2815
   case tCASEZ:
2816
      return p_case_statement();
54✔
2817
   case tIFIMPL:
1✔
2818
      return p_event_trigger();
1✔
2819
   case tASSIGN:
4✔
2820
   case tDEASSIGN:
2821
   case tFORCE:
2822
   case tRELEASE:
2823
      {
2824
         vlog_node_t v = p_procedural_continuous_assignment();
4✔
2825
         consume(tSEMI);
4✔
2826
         return v;
4✔
2827
      }
2828
   case tRETURN:
7✔
2829
      return p_jump_statement();
7✔
2830
   default:
2✔
2831
      one_of(tID, tAT, tHASH, tBEGIN, tFORK, tSYSTASK, tVOID, tIF, tFOREVER,
2✔
2832
             tWHILE, tREPEAT, tDO, tFOR, tWAIT, tCASE, tCASEX, tCASEZ, tIFIMPL,
2833
             tASSIGN, tDEASSIGN, tFORCE, tRELEASE, tRETURN);
2834
      drop_tokens_until(&state, tSEMI);
2✔
2835
      return vlog_new(V_BLOCK);  // Dummy statement
2✔
2836
   }
2837
}
2838

2839
static vlog_node_t p_statement(void)
23,833✔
2840
{
2841
   // [ block_identifier : ] { attribute_instance } statement_item
2842

2843
   BEGIN("statement");
47,666✔
2844

2845
   ident_t id = NULL;
23,833✔
2846
   if (peek() == tID && peek_nth(2) == tCOLON) {
23,833✔
2847
      id = p_identifier();
6✔
2848
      consume(tCOLON);
6✔
2849
   }
2850

2851
   optional_attributes();
23,833✔
2852

2853
   return p_statement_item(id);
23,833✔
2854
}
2855

2856
static vlog_node_t p_statement_or_null(void)
27,735✔
2857
{
2858
   // statement | { attribute_instance } ;
2859

2860
   BEGIN("statement or null");
55,470✔
2861

2862
   if (optional(tSEMI))
27,735✔
2863
      return NULL;
2864
   else
2865
      return p_statement();
23,531✔
2866
}
2867

2868
static vlog_node_t p_always_construct(void)
302✔
2869
{
2870
   // always_keyword statement
2871

2872
   BEGIN("always construct");
604✔
2873

2874
   vlog_node_t v = vlog_new(V_ALWAYS);
302✔
2875

2876
   switch (one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH)) {
302✔
2877
   case tALWAYSCOMB:  vlog_set_subkind(v, V_ALWAYS_COMB);  break;
1✔
2878
   case tALWAYSFF:    vlog_set_subkind(v, V_ALWAYS_FF);    break;
1✔
2879
   case tALWAYSLATCH: vlog_set_subkind(v, V_ALWAYS_LATCH); break;
5✔
2880
   default:           vlog_set_subkind(v, V_ALWAYS_PLAIN); break;
295✔
2881
   }
2882

2883
   vlog_set_ident(v, default_label("always"));
302✔
2884
   vlog_add_stmt(v, p_statement());
302✔
2885

2886
   vlog_set_loc(v, CURRENT_LOC);
302✔
2887
   return v;
302✔
2888
}
2889

2890
static vlog_node_t p_initial_construct(void)
639✔
2891
{
2892
   // initial statement_or_null
2893

2894
   BEGIN("initial construct");
1,278✔
2895

2896
   consume(tINITIAL);
639✔
2897

2898
   vlog_node_t v = vlog_new(V_INITIAL);
639✔
2899
   vlog_set_ident(v, default_label("initial"));
639✔
2900

2901
   vlog_node_t s = p_statement_or_null();
639✔
2902
   if (s != NULL)
639✔
2903
      vlog_add_stmt(v, s);
639✔
2904

2905
   vlog_set_loc(v, CURRENT_LOC);
639✔
2906
   return v;
639✔
2907
}
2908

2909
static vlog_node_t p_net_assignment(vlog_node_t delay, vlog_node_t strength)
475✔
2910
{
2911
   // net_lvalue = expression
2912

2913
   BEGIN("net assignment");
950✔
2914

2915
   vlog_symtab_set_implicit(symtab, implicit_kind);
475✔
2916

2917
   vlog_node_t v = vlog_new(V_ASSIGN);
475✔
2918
   vlog_set_target(v, p_net_lvalue());
475✔
2919
   vlog_set_ident(v, default_label("assign"));
475✔
2920
   vlog_set_delay(v, delay);
475✔
2921
   if (strength != NULL)
475✔
2922
      vlog_add_param(v, strength);
51✔
2923

2924
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
475✔
2925

2926
   consume(tEQ);
475✔
2927

2928
   vlog_set_value(v, p_expression());
475✔
2929

2930
   vlog_set_loc(v, CURRENT_LOC);
475✔
2931
   return v;
475✔
2932
}
2933

2934
static void p_list_of_net_assignments(vlog_node_t mod, vlog_node_t delay,
475✔
2935
                                      vlog_node_t strength)
2936
{
2937
   // net_assignment { , net_assignment }
2938

2939
   BEGIN("list of net assignments");
950✔
2940

2941
   do {
475✔
2942
      vlog_add_stmt(mod, p_net_assignment(delay, strength));
475✔
2943
   } while (optional(tCOMMA));
475✔
2944
}
475✔
2945

2946
static void p_continuous_assign(vlog_node_t mod)
475✔
2947
{
2948
   // assign [ drive_strength ] [ delay3 ] list_of_net_assignments ;
2949
   //   | assign [ delay_control ] list_of_variable_assignments ;
2950

2951
   BEGIN("continuous assignment");
950✔
2952

2953
   consume(tASSIGN);
475✔
2954

2955
   vlog_node_t delay = NULL;
475✔
2956
   vlog_node_t strength = NULL;
475✔
2957
   if (peek() == tLPAREN) {
475✔
2958
      strength = p_drive_strength();
51✔
2959
      if (peek() == tHASH)
51✔
2960
         p_delay3();
2✔
2961
   } else if (peek() == tHASH)
424✔
2962
      delay = p_delay_control();
12✔
2963

2964
   p_list_of_net_assignments(mod, delay, strength);
475✔
2965

2966
   consume(tSEMI);
475✔
2967
}
475✔
2968

2969
static vlog_net_kind_t p_net_type(void)
751✔
2970
{
2971
   // supply0 | supply1 | tri | triand | trior | trireg | tri0
2972
   //   | tri1 | uwire | wire | wand | wor
2973

2974
   BEGIN("net type");
1,502✔
2975

2976
   switch (one_of(tWIRE, tUWIRE, tSUPPLY0, tSUPPLY1, tTRI, tTRIAND,
751✔
2977
                  tTRIOR, tTRIREG, tTRI0, tTRI1, tWAND, tWOR)) {
2978
   case tSUPPLY0: return V_NET_SUPPLY0;
2979
   case tSUPPLY1: return V_NET_SUPPLY1;
4✔
2980
   case tTRI:     return V_NET_TRI;
1✔
2981
   case tTRIAND:  return V_NET_TRIAND;
2✔
2982
   case tTRIOR:   return V_NET_TRIOR;
2✔
2983
   case tTRIREG:  return V_NET_TRIREG;
1✔
2984
   case tTRI0:    return V_NET_TRI0;
4✔
2985
   case tTRI1:    return V_NET_TRI1;
2✔
2986
   case tUWIRE:   return V_NET_UWIRE;
1✔
2987
   case tWAND:    return V_NET_WAND;
1✔
2988
   case tWOR:     return V_NET_WOR;
1✔
2989
   case tWIRE:
724✔
2990
   default:       return V_NET_WIRE;
724✔
2991
   }
2992
}
2993

2994
static vlog_node_t p_net_decl_assignment(vlog_net_kind_t kind,
758✔
2995
                                         vlog_node_t datatype)
2996
{
2997
   // net_identifier { unpacked_dimension } [ = expression ]
2998

2999
   BEGIN("net declaration assignment");
1,516✔
3000

3001
   vlog_node_t v = vlog_new(V_NET_DECL);
758✔
3002
   vlog_set_subkind(v, kind);
758✔
3003
   vlog_set_type(v, datatype);
758✔
3004
   vlog_set_ident(v, p_identifier());
758✔
3005

3006
   while (peek() == tLSQUARE)
772✔
3007
      vlog_add_range(v, p_unpacked_dimension());
14✔
3008

3009
   if (optional(tEQ))
758✔
3010
      vlog_set_value(v, p_expression());
261✔
3011

3012
   vlog_set_loc(v, CURRENT_LOC);
758✔
3013
   vlog_symtab_put(symtab, v);
758✔
3014
   return v;
758✔
3015
}
3016

3017
static void p_list_of_net_decl_assignments(vlog_node_t mod,
665✔
3018
                                           vlog_net_kind_t kind,
3019
                                           vlog_node_t datatype)
3020
{
3021
   // net_decl_assignment { , net_decl_assignment }
3022

3023
   BEGIN("list of net declaration assignments");
1,330✔
3024

3025
   do {
758✔
3026
      vlog_node_t v = p_net_decl_assignment(kind, datatype);
758✔
3027
      vlog_add_decl(mod, v);
758✔
3028
   } while (optional(tCOMMA));
758✔
3029
}
665✔
3030

3031
static vlog_node_t p_drive_strength(void)
55✔
3032
{
3033
   //( strength0 , strength1 ) | ( strength1 , strength0 )
3034
   //| ( strength0 , highz1 )  | ( strength1 , highz0 )
3035
   //| ( highz0 , strength1 )  | ( highz1 , strength0 )
3036

3037
   BEGIN("drive strength");
110✔
3038

3039
   consume(tLPAREN);
55✔
3040

3041
   vlog_strength_t s0, s1;
55✔
3042
   switch (peek()) {
55✔
3043
   case tSUPPLY0:
5✔
3044
   case tSTRONG0:
3045
   case tPULL0:
3046
   case tWEAK0:
3047
      {
3048
         s0 = p_strength0();
5✔
3049
         consume(tCOMMA);
5✔
3050
         if (optional(tHIGHZ1))
5✔
3051
            s1 = V_STRENGTH_HIGHZ;
3052
         else
3053
            s1 = p_strength1();
4✔
3054
      }
3055
      break;
3056
   case tHIGHZ0:
1✔
3057
      {
3058
         s0 = V_STRENGTH_HIGHZ;
1✔
3059
         consume(tHIGHZ0);
1✔
3060
         consume(tCOMMA);
1✔
3061
         s1 = p_strength1();
1✔
3062
      }
3063
      break;
1✔
3064
   case tSUPPLY1:
48✔
3065
   case tSTRONG1:
3066
   case tPULL1:
3067
   case tWEAK1:
3068
      {
3069
         s1 = p_strength1();
48✔
3070
         consume(tCOMMA);
48✔
3071
         if (optional(tHIGHZ0))
48✔
3072
            s0 = V_STRENGTH_HIGHZ;
3073
         else
3074
            s0 = p_strength0();
48✔
3075
      }
3076
      break;
3077
   case tHIGHZ1:
1✔
3078
      {
3079
         s1 = V_STRENGTH_HIGHZ;
1✔
3080
         consume(tHIGHZ1);
1✔
3081
         consume(tCOMMA);
1✔
3082
         s0 = p_strength0();
1✔
3083
      }
3084
      break;
1✔
UNCOV
3085
   default:
×
3086
      should_not_reach_here();
3087
   }
3088

3089
   consume(tRPAREN);
55✔
3090

3091
   vlog_node_t v = vlog_new(V_STRENGTH);
55✔
3092
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
55✔
3093
   vlog_set_loc(v, CURRENT_LOC);
55✔
3094

3095
   return v;
55✔
3096
}
3097

3098
static vlog_strength_t p_charge_strength(void)
2✔
3099
{
3100
   // ( small ) | ( medium ) | ( large )
3101

3102
   BEGIN("drive charge");
4✔
3103

3104
   consume(tLPAREN);
2✔
3105

3106
   vlog_strength_t s;
2✔
3107
   switch (one_of(tSMALL, tMEDIUM, tLARGE)) {
2✔
3108
   default:
3109
   case tSMALL:  s = V_STRENGTH_SMALL;
3110
   case tMEDIUM: s = V_STRENGTH_MEDIUM;
2✔
3111
   case tLARGE:  s = V_STRENGTH_LARGE;
2✔
3112
   }
3113

3114
   consume(tRPAREN);
2✔
3115

3116
   return s;
2✔
3117
}
3118

3119
static void p_net_declaration(vlog_node_t mod)
666✔
3120
{
3121
   // net_type [ drive_strength | charge_strength ] [ vectored | scalared ]
3122
   //     data_type_or_implicit [ delay3 ] list_of_net_decl_assignments ;
3123
   //  | net_type_identifier [ delay_control ] list_of_net_decl_assignments ;
3124
   //  | interconnect implicit_data_type [ # delay_value ] net_identifier
3125
   //     { unpacked_dimension } [ , net_identifier { unpacked_dimension } ] ;
3126

3127
   BEGIN("net declaration");
1,332✔
3128

3129
   ident_t id;
666✔
3130
   vlog_node_t dt;
666✔
3131
   vlog_net_kind_t kind = V_NET_WIRE;
666✔
3132

3133
   switch (peek()) {
666✔
3134
   case tINTERCONNECT:
1✔
3135
      {
3136
         consume(tINTERCONNECT);
1✔
3137

3138
         dt = p_implicit_data_type();
1✔
3139

3140
         if (optional(tHASH))
1✔
3141
            p_delay_value();
1✔
3142

3143
         do {
1✔
3144
            id = p_identifier();
1✔
3145
            if (peek() == tLSQUARE)
1✔
3146
               p_unpacked_dimension();
1✔
3147
         } while (optional(tCOMMA));
1✔
3148
      }
3149
      break;
3150

3151
   case tID:
×
3152
      {
UNCOV
3153
         id = p_identifier();
×
UNCOV
3154
         dt = vlog_symtab_query(symtab, id);
×
UNCOV
3155
         if (dt == NULL)
×
3156
            should_not_reach_here();
3157
         // TODO check that the identifier is actually
3158
         // a user declared nettype
3159

UNCOV
3160
         if (peek() == tHASH)
×
3161
            p_delay_control();
×
3162

UNCOV
3163
         p_list_of_net_decl_assignments(mod, kind, dt);
×
3164
      }
UNCOV
3165
      break;
×
3166

3167
   default:
665✔
3168
      {
3169
         kind = p_net_type();
665✔
3170

3171
         if (peek() == tLPAREN) {
665✔
3172
            switch (peek_nth(2)) {
4✔
3173
            case tHIGHZ0:
2✔
3174
            case tHIGHZ1:
3175
            case tSUPPLY0:
3176
            case tSUPPLY1:
3177
            case tSTRONG0:
3178
            case tSTRONG1:
3179
            case tPULL0:
3180
            case tPULL1:
3181
            case tWEAK0:
3182
            case tWEAK1:
3183
               p_drive_strength();
2✔
3184
               break;
2✔
3185
            case tSMALL:
2✔
3186
            case tMEDIUM:
3187
            case tLARGE:
3188
               if (kind != V_NET_TRIREG)
2✔
3189
                  parse_error(&state.last_loc, "charge strength only allowed "
1✔
3190
                              "with the trireg keyword");
3191
               p_charge_strength();
2✔
3192
               break;
2✔
3193
            default:
×
UNCOV
3194
               one_of(tHIGHZ0, tHIGHZ1, tSUPPLY0, tSUPPLY1, tSTRONG0, tSTRONG1,
×
3195
                     tPULL0, tPULL1, tWEAK0, tWEAK1, tSMALL, tMEDIUM, tLARGE);
UNCOV
3196
               drop_tokens_until(&state, tSEMI);
×
UNCOV
3197
               return;
×
3198
            }
3199
         }
3200

3201
         bool need_packed = false;
665✔
3202
         if (optional(tVECTORED) || optional(tSCALARED))
665✔
3203
            need_packed = true;
3204

3205
         dt = p_data_type_or_implicit();
665✔
3206

3207
         if (need_packed) {
665✔
3208
            bool has_packed = false;
2✔
3209
            unsigned ranges = vlog_ranges(dt);
2✔
3210
            for (unsigned i = 0; i < ranges; i++) {
3✔
3211
               vlog_node_t r = vlog_range(dt, i);
1✔
3212
               if (vlog_subkind(r) == V_DIM_PACKED)
1✔
3213
                  has_packed |= true;
1✔
3214
            }
3215
            if (!has_packed)
2✔
3216
               parse_error(&state.last_loc, "vectored and scalared keywords "
1✔
3217
                           "are only allowed with at least a packed dimension");
3218
         }
3219

3220
         if (peek() == tHASH)
665✔
3221
            p_delay3();
5✔
3222

3223
         p_list_of_net_decl_assignments(mod, kind, dt);
665✔
3224
      }
3225
   }
3226

3227
   consume(tSEMI);
666✔
3228
}
3229

3230
static vlog_node_t p_unsized_dimension(void)
1✔
3231
{
3232
   // [ ]
3233

3234
   BEGIN("unsized dimension");
2✔
3235

3236
   consume(tLSQUARE);
1✔
3237
   consume(tRSQUARE);
1✔
3238

3239
   vlog_node_t v = vlog_new(V_DIMENSION);
1✔
3240
   vlog_set_subkind(v, V_DIM_UNSIZED);
1✔
3241
   vlog_set_loc(v, CURRENT_LOC);
1✔
3242

3243
   return v;
1✔
3244
}
3245

3246
static vlog_node_t p_variable_dimension(void)
71✔
3247
{
3248
   // unsized_dimension | unpacked_dimension | associative_dimension
3249
   //   | queue_dimension
3250

3251
   BEGIN("variable dimension");
142✔
3252

3253
   switch (peek_nth(2)) {
71✔
3254
   case tRSQUARE:
1✔
3255
      return p_unsized_dimension();
1✔
3256
   default:
70✔
3257
      return p_unpacked_dimension();
70✔
3258
   }
3259
}
3260

3261
static vlog_node_t p_variable_decl_assignment(vlog_node_t datatype)
3,768✔
3262
{
3263
   // variable_identifier { variable_dimension } [ = expression ]
3264
   //   | dynamic_array_variable_identifier unsized_dimension
3265
   //       { variable_dimension } [ = dynamic_array_new ]
3266
   //   | class_variable_identifier [ = class_new ]
3267

3268
   BEGIN("variable declaration assignment");
7,536✔
3269

3270
   vlog_node_t v = vlog_new(V_VAR_DECL);
3,768✔
3271
   vlog_set_ident(v, p_identifier());
3,768✔
3272
   vlog_set_type(v, datatype);
3,768✔
3273

3274
   while (peek() == tLSQUARE)
3,839✔
3275
      vlog_add_range(v, p_variable_dimension());
71✔
3276

3277
   if (optional(tEQ))
3,768✔
3278
      vlog_set_value(v, p_expression());
167✔
3279

3280
   vlog_set_loc(v, CURRENT_LOC);
3,768✔
3281
   vlog_symtab_put(symtab, v);
3,768✔
3282
   return v;
3,768✔
3283
}
3284

3285
static void p_list_of_variable_decl_assignments(vlog_node_t parent,
3,326✔
3286
                                                vlog_node_t datatype)
3287
{
3288
   // variable_decl_assignment { , variable_decl_assignment }
3289

3290
   BEGIN("list of variable declaration assignments");
6,652✔
3291

3292
   do {
3,768✔
3293
      vlog_add_decl(parent, p_variable_decl_assignment(datatype));
3,768✔
3294
   } while (optional(tCOMMA));
3,768✔
3295
}
3,326✔
3296

3297
static vlog_node_t p_type_declaration(void)
12✔
3298
{
3299
   // typedef data_type type_identifier { variable_dimension } ;
3300
   //   | typedef interface_instance_identifier constant_bit_select .
3301
   //       type_identifier type_identifier ;
3302
   //   | typedef [ enum | struct | union | class | interface class ]
3303
   //       type_identifier ;
3304

3305
   BEGIN("type declaration");
24✔
3306

3307
   consume(tTYPEDEF);
12✔
3308

3309
   vlog_node_t v = vlog_new(V_TYPE_DECL);
12✔
3310
   vlog_set_type(v, p_data_type());
12✔
3311
   vlog_set_ident(v, p_identifier());
12✔
3312

3313
   consume(tSEMI);
12✔
3314

3315
   vlog_set_loc(v, CURRENT_LOC);
12✔
3316
   vlog_symtab_put(symtab, v);
12✔
3317
   return v;
12✔
3318
}
3319

3320
static vlog_node_t p_package_import_item(void)
3✔
3321
{
3322
   // package_identifier :: identifier | package_identifier :: *
3323

3324
   BEGIN("package import item");
6✔
3325

3326
   vlog_node_t pack = p_package_identifier();
3✔
3327

3328
   vlog_node_t v = vlog_new(V_IMPORT_DECL);
3✔
3329
   vlog_set_ref(v, pack);
3✔
3330

3331
   consume(tSCOPE);
3✔
3332

3333
   if (peek() == tID)
3✔
3334
      vlog_set_ident(v, p_identifier());
1✔
3335
   else
3336
      one_of(tTIMES, tID);
2✔
3337

3338
   vlog_set_loc(v, CURRENT_LOC);
3✔
3339
   vlog_symtab_import(symtab, v);
3✔
3340
   return v;
3✔
3341
}
3342

3343
static void p_package_import_declaration(vlog_node_t parent)
3✔
3344
{
3345
   // import package_import_item { , package_import_item } ;
3346

3347
   BEGIN("package import declaration");
6✔
3348

3349
   consume(tIMPORT);
3✔
3350

3351
   do {
3✔
3352
      vlog_add_decl(parent, p_package_import_item());
3✔
3353
   } while (optional(tCOMMA));
3✔
3354

3355
   consume(tSEMI);
3✔
3356
}
3✔
3357

3358
static void p_data_declaration(vlog_node_t mod)
3,329✔
3359
{
3360
   // [ const ] [ var ] [ lifetime ] data_type_or_implicit
3361
   //     list_of_variable_decl_assignments ;
3362
   //  | type_declaration | package_import_declaration | net_type_declaration
3363

3364
   BEGIN("data declaration");
6,658✔
3365

3366
   switch (peek()) {
3,329✔
3367
   case tTYPEDEF:
12✔
3368
      vlog_add_decl(mod, p_type_declaration());
12✔
3369
      break;
12✔
3370
   case tIMPORT:
3✔
3371
      p_package_import_declaration(mod);
3✔
3372
      break;
3✔
3373
   default:
3,314✔
3374
      {
3375
         optional(tVAR);
3,314✔
3376

3377
         vlog_node_t dt = p_data_type_or_implicit();
3,314✔
3378
         p_list_of_variable_decl_assignments(mod, dt);
3,314✔
3379

3380
         consume(tSEMI);
3,314✔
3381
      }
3382
   }
3383
}
3,329✔
3384

3385
static v_port_kind_t p_port_direction(void)
106✔
3386
{
3387
   // input | output | inout | ref
3388

3389
   BEGIN("port direction");
212✔
3390

3391
   switch (one_of(tINPUT, tOUTPUT, tINOUT)) {
106✔
3392
   case tINPUT:  return V_PORT_INPUT;
3393
   case tOUTPUT: return V_PORT_OUTPUT;
4✔
3394
   case tINOUT:  return V_PORT_INOUT;
1✔
3395
   default:      return V_PORT_INPUT;
3396
   }
3397
}
3398

3399
static v_port_kind_t p_tf_port_direction(void)
106✔
3400
{
3401
   // port_direction | const ref
3402

3403
   BEGIN("task or function port direction");
212✔
3404

3405
   return p_port_direction();
106✔
3406
}
3407

3408
static vlog_node_t p_tf_port_item(void)
47✔
3409
{
3410
   // { attribute_instance } [ tf_port_direction ] [ var ]
3411
   //    data_type_or_implicit [ port_identifier { variable_dimension }
3412
   //    [ = expression ] ]
3413

3414
   BEGIN("task or function port item");
94✔
3415

3416
   vlog_node_t v = vlog_new(V_TF_PORT_DECL);
47✔
3417

3418
   skip_over_attributes();
47✔
3419

3420
   if (scan(tINPUT, tOUTPUT, tINOUT))
47✔
3421
      vlog_set_subkind(v, p_tf_port_direction());
36✔
3422
   else
3423
      vlog_set_subkind(v, V_PORT_INPUT);
11✔
3424

3425
   vlog_set_type(v, p_data_type_or_implicit());
47✔
3426

3427
   if (peek() == tID) {
47✔
3428
      vlog_set_ident(v, p_identifier());
46✔
3429

3430
      if (optional(tEQ))
46✔
3431
         vlog_set_value(v, p_expression());
2✔
3432
   }
3433

3434
   vlog_set_loc(v, CURRENT_LOC);
47✔
3435
   return v;
47✔
3436
}
3437

3438
static void p_tf_port_list(vlog_node_t tf)
35✔
3439
{
3440
   // tf_port_item { , tf_port_item }
3441

3442
   BEGIN("task or function port list");
70✔
3443

3444
   do {
45✔
3445
      vlog_node_t v = p_tf_port_item();
45✔
3446
      vlog_add_port(tf, v);
45✔
3447

3448
      if (vlog_has_ident(v))  // Ignore unnamed ports
45✔
3449
         vlog_symtab_put(symtab, v);
44✔
3450
   } while (optional(tCOMMA));
45✔
3451
}
35✔
3452

3453
static void p_list_of_tf_variable_identifiers(vlog_node_t tf,
70✔
3454
                                              v_port_kind_t kind,
3455
                                              vlog_node_t dt)
3456
{
3457
   // port_identifier { variable_dimension } [ = expression ]
3458
   //    { , port_identifier { variable_dimension } [ = expression ] }
3459

3460
   BEGIN("list of task or function variable identifiers");
140✔
3461

3462
   do {
80✔
3463
      vlog_node_t v = vlog_new(V_TF_PORT_DECL);
80✔
3464
      vlog_set_subkind(v, kind);
80✔
3465
      vlog_set_type(v, dt);
80✔
3466
      vlog_set_ident(v, p_identifier());
80✔
3467
      vlog_set_loc(v, &state.last_loc);
80✔
3468

3469
      if (optional(tEQ))
80✔
3470
         vlog_set_value(v, p_expression());
1✔
3471

3472
      vlog_add_port(tf, v);
80✔
3473
      vlog_symtab_put(symtab, v);
80✔
3474
   } while (optional(tCOMMA));
80✔
3475
}
70✔
3476

3477
static void p_tf_port_declaration(vlog_node_t tf)
70✔
3478
{
3479
   // { attribute_instance } tf_port_direction [ var ] data_type_or_implicit
3480
   //    list_of_tf_variable_identifiers ;
3481

3482
   BEGIN("task or function port declaration");
140✔
3483

3484
   v_port_kind_t kind = p_tf_port_direction();
70✔
3485

3486
   optional(tVAR);
70✔
3487

3488
   vlog_node_t dt = p_data_type_or_implicit();
70✔
3489

3490
   p_list_of_tf_variable_identifiers(tf, kind, dt);
70✔
3491

3492
   consume(tSEMI);
70✔
3493
}
70✔
3494

3495
static void p_tf_item_declaration(vlog_node_t tf)
92✔
3496
{
3497
   // block_item_declaration | tf_port_declaration
3498

3499
   BEGIN("task or function item declaration");
184✔
3500

3501
   switch (peek()) {
92✔
3502
   case tINPUT:
70✔
3503
   case tOUTPUT:
3504
   case tCONST:
3505
      p_tf_port_declaration(tf);
70✔
3506
      break;
70✔
3507
   default:
22✔
3508
      p_block_item_declaration(tf);
22✔
3509
      break;
22✔
3510
   }
3511
}
92✔
3512

3513
static void p_task_body_declaration(vlog_node_t task)
35✔
3514
{
3515
   // [ interface_identifier . | class_scope ] task_identifier ;
3516
   //    { tf_item_declaration } { statement_or_null }
3517
   //    endtask [ : task_identifier ]
3518
   // | [ interface_identifier . | class_scope ] task_identifier
3519
   //    ( [ tf_port_list ] ) ; { block_item_declaration }
3520
   //    { statement_or_null } endtask [ : task_identifier ]
3521

3522
   BEGIN("task body declaration");
70✔
3523

3524
   ident_t id = p_identifier();
35✔
3525
   vlog_set_ident(task, id);
35✔
3526
   vlog_set_loc(task, &state.last_loc);
35✔
3527

3528
   vlog_symtab_put(symtab, task);
35✔
3529

3530
   vlog_symtab_push(symtab, task);
35✔
3531

3532
   if (optional(tLPAREN)) {
35✔
3533
      if (peek() != tRPAREN)
7✔
3534
         p_tf_port_list(task);
7✔
3535
      consume(tRPAREN);
7✔
3536

3537
      consume(tSEMI);
7✔
3538

3539
      skip_over_attributes();
7✔
3540

3541
      while (scan_block_item_declaration()) {
7✔
UNCOV
3542
         p_block_item_declaration(task);
×
UNCOV
3543
         skip_over_attributes();
×
3544
      }
3545
   }
3546
   else {
3547
      consume(tSEMI);
28✔
3548

3549
      skip_over_attributes();
28✔
3550

3551
      while (scan_tf_item_declaration()) {
67✔
3552
         p_tf_item_declaration(task);
39✔
3553
         skip_over_attributes();
39✔
3554
      }
3555
   }
3556

3557
   while (not_at_token(tENDTASK)) {
70✔
3558
      vlog_node_t s = p_statement_or_null();
35✔
3559
      if (s != NULL)
35✔
3560
         vlog_add_stmt(task, s);
35✔
3561
   }
3562

3563
   consume(tENDTASK);
35✔
3564

3565
   if (optional(tCOLON)) {
35✔
3566
      ident_t name = p_identifier();
2✔
3567
      if (id != name)
2✔
3568
         error_at(&state.last_loc, "'%s' does not match task name '%s'",
1✔
3569
                  istr(name), istr(id));
3570
   }
3571

3572
   vlog_symtab_pop(symtab);
35✔
3573
}
35✔
3574

3575
static void p_lifetime(void)
1✔
3576
{
3577
   // static | automatic
3578

3579
   BEGIN("lifetime");
2✔
3580

3581
   one_of(tAUTOMATIC);
1✔
3582
}
1✔
3583

3584
static vlog_node_t p_task_declaration(void)
35✔
3585
{
3586
   // task [ dynamic_override_specifiers ] [ lifetime ] task_body_declaration
3587

3588
   BEGIN("task declaration");
70✔
3589

3590
   vlog_node_t v = vlog_new(V_TASK_DECL);
35✔
3591

3592
   consume(tTASK);
35✔
3593

3594
   if (scan(tAUTOMATIC))
35✔
UNCOV
3595
      p_lifetime();
×
3596

3597
   p_task_body_declaration(v);
35✔
3598

3599
   vlog_set_loc(v, CURRENT_LOC);
35✔
3600
   return v;
35✔
3601
}
3602

3603
static vlog_node_t p_function_data_type_or_implicit(void)
72✔
3604
{
3605
   // data_type_or_void | implicit_data_type
3606

3607
   BEGIN("function data type or implicit");
144✔
3608

3609
   switch (peek()) {
72✔
3610
   case tREG:
17✔
3611
   case tSTRUCT:
3612
   case tUNION:
3613
   case tENUM:
3614
   case tSVINT:
3615
   case tINTEGER:
3616
   case tSVREAL:
3617
   case tSHORTREAL:
3618
   case tREALTIME:
3619
   case tLOGIC:
3620
   case tBIT:
3621
   case tSHORTINT:
3622
   case tSTRINGK:
3623
   case tEVENT:
3624
   case tVOID:
3625
      return p_data_type_or_void();
17✔
3626
   case tID:
9✔
3627
      {
3628
         vlog_node_t dt = peek_reference();
9✔
3629
         if (dt != NULL && is_data_type(dt)) {
9✔
3630
            consume(tID);
1✔
3631
            return dt;
1✔
3632
         }
3633
         else
3634
            return p_implicit_data_type();
8✔
3635
      }
3636
   default:
46✔
3637
      return p_implicit_data_type();
46✔
3638
   }
3639
}
3640

3641
static void p_function_body_declaration(vlog_node_t func)
72✔
3642
{
3643
   // function_data_type_or_implicit [ interface_identifier . | class_scope ]
3644
   //    function_identifier ; { tf_item_declaration }
3645
   //    { function_statement_or_null } endfunction [ : function_identifier ]
3646
   // | function_data_type_or_implicit [ interface_identifier . | class_scope ]
3647
   //    function_identifier ( [ tf_port_list ] ) ; { block_item_declaration }
3648
   //    { function_statement_or_null } endfunction [ : function_identifier ]
3649

3650
   BEGIN("function body declaration");
144✔
3651

3652
   vlog_set_type(func, p_function_data_type_or_implicit());
72✔
3653

3654
   ident_t id = p_identifier();
72✔
3655
   vlog_set_ident(func, id);
72✔
3656
   vlog_set_loc(func, &state.last_loc);
72✔
3657

3658
   vlog_symtab_put(symtab, func);
72✔
3659

3660
   vlog_symtab_push(symtab, func);
72✔
3661

3662
   if (optional(tLPAREN)) {
72✔
3663
      if (peek() != tRPAREN)
31✔
3664
         p_tf_port_list(func);
28✔
3665
      consume(tRPAREN);
31✔
3666

3667
      consume(tSEMI);
31✔
3668

3669
      skip_over_attributes();
31✔
3670

3671
      while (scan_block_item_declaration()) {
35✔
3672
         p_block_item_declaration(func);
4✔
3673
         skip_over_attributes();
4✔
3674
      }
3675
   }
3676
   else {
3677
      consume(tSEMI);
41✔
3678

3679
      skip_over_attributes();
41✔
3680

3681
      while (scan_tf_item_declaration()) {
94✔
3682
         p_tf_item_declaration(func);
53✔
3683
         skip_over_attributes();
53✔
3684
      }
3685
   }
3686

3687
   while (not_at_token(tENDFUNCTION)) {
150✔
3688
      vlog_node_t s = p_statement_or_null();
78✔
3689
      if (s != NULL)
78✔
3690
         vlog_add_stmt(func, s);
78✔
3691
   }
3692

3693
   consume(tENDFUNCTION);
72✔
3694

3695
   if (optional(tCOLON)) {
72✔
3696
      ident_t name = p_identifier();
3✔
3697
      if (id != name)
3✔
3698
         error_at(&state.last_loc, "'%s' does not match function name '%s'",
1✔
3699
                  istr(name), istr(id));
3700
   }
3701

3702
   vlog_symtab_pop(symtab);
72✔
3703
}
72✔
3704

3705
static vlog_node_t p_function_declaration(void)
72✔
3706
{
3707
   // function [ lifetime ] function_body_declaration
3708

3709
   BEGIN("function declaration");
144✔
3710

3711
   vlog_node_t v = vlog_new(V_FUNC_DECL);
72✔
3712

3713
   consume(tFUNCTION);
72✔
3714

3715
   if (scan(tAUTOMATIC))
72✔
3716
      p_lifetime();
1✔
3717

3718
   p_function_body_declaration(v);
72✔
3719

3720
   vlog_set_loc(v, CURRENT_LOC);
72✔
3721
   return v;
72✔
3722
}
3723

3724
static vlog_node_t p_constant_param_expression(void)
358✔
3725
{
3726
   // mintypmax_expression | data_type | $
3727

3728
   BEGIN("constant parameter expression");
716✔
3729

3730
   return p_mintypmax_expression();
358✔
3731
}
3732

3733
static vlog_node_t p_param_assignment(vlog_node_t datatype, vlog_kind_t kind)
374✔
3734
{
3735
   // parameter_identifier { unpacked_dimension }
3736
   //   [ = constant_param_expression ]
3737

3738
   BEGIN("parameter assignment");
748✔
3739

3740
   vlog_node_t v = vlog_new(kind);
374✔
3741
   vlog_set_ident(v, p_identifier());
374✔
3742
   vlog_set_type(v, datatype);
374✔
3743

3744
   if (optional(tEQ))
374✔
3745
      vlog_set_value(v, p_constant_param_expression());
358✔
3746

3747
   vlog_set_loc(v, CURRENT_LOC);
374✔
3748
   return v;
374✔
3749
}
3750

3751
static void p_list_of_param_assignments(vlog_node_t parent,
312✔
3752
                                        vlog_node_t datatype,
3753
                                        vlog_kind_t kind)
3754
{
3755
   // param_assignment { , param_assignment }
3756

3757
   BEGIN("list of parameter assignments");
624✔
3758

3759
   do {
374✔
3760
      vlog_node_t v = p_param_assignment(datatype, kind);
374✔
3761
      vlog_symtab_put(symtab, v);
374✔
3762
      vlog_add_decl(parent, v);
374✔
3763
   } while (peek_nth(2) == tID && optional(tCOMMA));
374✔
3764
}
312✔
3765

3766
static void p_parameter_declaration(vlog_node_t mod)
197✔
3767
{
3768
   // parameter data_type_or_implicit list_of_param_assignments
3769

3770
   BEGIN("parameter declaration");
394✔
3771

3772
   consume(tPARAMETER);
197✔
3773

3774
   vlog_node_t dt = p_data_type_or_implicit();
197✔
3775
   p_list_of_param_assignments(mod, dt, param_kind);
197✔
3776
}
197✔
3777

3778
static void p_local_parameter_declaration(vlog_node_t mod)
113✔
3779
{
3780
   // localparam data_type_or_implicit list_of_param_assignments
3781

3782
   BEGIN("local parameter declaration");
226✔
3783

3784
   consume(tLOCALPARAM);
113✔
3785

3786
   vlog_node_t dt = p_data_type_or_implicit();
113✔
3787
   p_list_of_param_assignments(mod, dt, V_LOCALPARAM);
113✔
3788
}
113✔
3789

3790
static void p_class_property(vlog_node_t parent)
15✔
3791
{
3792
   // { property_qualifier } data_declaration
3793
   //   | const { class_item_qualifier } data_type const_identifier
3794
   //       [ = constant_expression ] ;
3795

3796
   BEGIN("class property");
30✔
3797

3798
   p_data_declaration(parent);
15✔
3799
}
15✔
3800

3801
static void p_class_constructor_arg(vlog_node_t parent)
2✔
3802
{
3803
   // tf_port_item | default
3804

3805
   BEGIN("class constructor argument");
4✔
3806

3807
   vlog_node_t v = p_tf_port_item();
2✔
3808
   vlog_symtab_put(symtab, v);
2✔
3809
   vlog_add_param(parent, v);
2✔
3810
}
2✔
3811

3812
static void p_class_constructor_arg_list(vlog_node_t parent)
2✔
3813
{
3814
   // class_constructor_arg { , class_constructor_arg }
3815

3816
   BEGIN("class constructor argument list");
4✔
3817

3818
   do {
2✔
3819
      p_class_constructor_arg(parent);
2✔
3820
   } while (optional(tCOMMA));
2✔
3821
}
2✔
3822

3823
static vlog_node_t p_class_constructor_declaration(void)
2✔
3824
{
3825
   // function [ class_scope ] new [ ( [ class_constructor_arg_list ] ) ] ;
3826
   //   { block_item_declaration }
3827
   //   [ super . new [ ( [ list_of_arguments | default ] ) ] ; ]
3828
   //   { function_statement_or_null }
3829
   //   endfunction [ : new]
3830

3831
   BEGIN("class constructor declaration");
4✔
3832

3833
   consume(tFUNCTION);
2✔
3834
   consume(tNEW);
2✔
3835

3836
   vlog_node_t v = vlog_new(V_CONSTRUCTOR);
2✔
3837
   vlog_set_ident(v, ident_new("new"));
2✔
3838

3839
   vlog_symtab_push(symtab, v);
2✔
3840

3841
   if (optional(tLPAREN)) {
2✔
3842
      if (not_at_token(tRPAREN))
2✔
3843
         p_class_constructor_arg_list(v);
2✔
3844

3845
      consume(tRPAREN);
2✔
3846
   }
3847

3848
   consume(tSEMI);
2✔
3849

3850
   skip_over_attributes();
2✔
3851

3852
   while (scan_block_item_declaration()) {
2✔
UNCOV
3853
      p_block_item_declaration(v);
×
UNCOV
3854
      skip_over_attributes();
×
3855
   }
3856

3857
   if (optional(tSUPER)) {
2✔
3858
      consume(tDOT);
1✔
3859
      consume(tNEW);
1✔
3860

3861
      vlog_node_t call = vlog_new(V_SUPER_CALL);
1✔
3862
      vlog_set_loc(call, &state.last_loc);
1✔
3863

3864
      if (optional(tLPAREN)) {
1✔
3865
         p_list_of_arguments(call);
1✔
3866
         consume(tRPAREN);
1✔
3867
      }
3868

3869
      vlog_add_stmt(v, call);
1✔
3870
   }
3871

3872
   while (not_at_token(tENDFUNCTION)) {
5✔
3873
      vlog_node_t s = p_statement_or_null();
3✔
3874
      if (s != NULL)
3✔
3875
         vlog_add_stmt(v, s);
2✔
3876
   }
3877

3878
   consume(tENDFUNCTION);
2✔
3879

3880
   if (optional(tCOLON))
2✔
3881
      consume(tNEW);
2✔
3882

3883
   vlog_symtab_pop(symtab);
2✔
3884

3885
   vlog_set_loc(v, CURRENT_LOC);
2✔
3886
   return v;
2✔
3887
}
3888

3889
static void p_method_qualifier(void)
1✔
3890
{
3891
   // [ pure ] virtual | class_item_qualifier
3892

3893
   BEGIN("method qualifier");
2✔
3894

3895
   consume(tVIRTUAL);
1✔
3896
}
1✔
3897

3898
static void p_class_method(vlog_node_t class)
3✔
3899
{
3900
   // { method_qualifier } task_declaration
3901
   //    | { method_qualifier } function_declaration
3902
   //    | pure virtual { class_item_qualifier } method_prototype ;
3903
   //    | extern { method_qualifier } method_prototype ;
3904
   //    | { method_qualifier } class_constructor_declaration
3905
   //    | extern { method_qualifier } class_constructor_prototype
3906

3907
   BEGIN("class method");
6✔
3908

3909
   if (scan(tVIRTUAL))
3✔
3910
      p_method_qualifier();
1✔
3911

3912
   switch (peek()) {
3✔
3913
   case tFUNCTION:
3✔
3914
      if (peek_nth(2) == tNEW)
3✔
3915
         vlog_add_decl(class, p_class_constructor_declaration());
2✔
3916
      else
3917
         vlog_add_decl(class, p_function_declaration());
1✔
3918
      break;
UNCOV
3919
   default:
×
UNCOV
3920
      one_of(tFUNCTION);
×
UNCOV
3921
      break;
×
3922
   }
3923
}
3✔
3924

3925
static void p_class_item(vlog_node_t parent)
19✔
3926
{
3927
   // { attribute_instance } class_property
3928
   //   | { attribute_instance } class_method
3929
   //   | { attribute_instance } class_constraint
3930
   //   | { attribute_instance } class_declaration
3931
   //   | { attribute_instance } covergroup_declaration
3932
   //   | local_parameter_declaration ;
3933
   //   | parameter_declaration | ;
3934

3935
   BEGIN("class item");
38✔
3936

3937
   optional_attributes();
19✔
3938

3939
   switch (peek()) {
19✔
3940
   case tSEMI:
1✔
3941
      consume(tSEMI);
1✔
3942
      break;
1✔
3943
   case tFUNCTION:
3✔
3944
   case tTASK:
3945
   case tVIRTUAL:
3946
      p_class_method(parent);
3✔
3947
      break;
3✔
3948
   default:
15✔
3949
      p_class_property(parent);
15✔
3950
      break;
15✔
3951
   }
3952
}
19✔
3953

3954
static void p_class_type(void)
2✔
3955
{
3956
   // ps_class_identifier [ parameter_value_assignment ]
3957
   //   { :: class_identifier [ parameter_value_assignment ] }
3958

3959
   BEGIN("class type");
4✔
3960

3961
   (void)p_identifier();
2✔
3962
}
2✔
3963

3964
static vlog_node_t p_class_declaration(void)
12✔
3965
{
3966
   // [ virtual ] class [ lifetime ] class_identifier [ parameter_port_list ]
3967
   //   [ extends class_type [ ( list_of_arguments ) ] ]
3968
   //   [ implements interface_class_type { , interface_class_type } ] ;
3969
   //   { class_item } endclass [ : class_identifier ]
3970

3971
   BEGIN("class declaration");
24✔
3972

3973
   vlog_node_t v = vlog_new(V_CLASS_DECL);
12✔
3974

3975
   optional(tVIRTUAL);
12✔
3976

3977
   consume(tCLASS);
12✔
3978

3979
   ident_t name = p_identifier();
12✔
3980
   vlog_set_ident(v, name);
12✔
3981

3982
   if (optional(tEXTENDS))
12✔
3983
      p_class_type();
2✔
3984

3985
   consume(tSEMI);
12✔
3986

3987
   vlog_symtab_push(symtab, v);
12✔
3988

3989
   while (not_at_token(tENDCLASS))
31✔
3990
      p_class_item(v);
19✔
3991

3992
   vlog_symtab_pop(symtab);
12✔
3993

3994
   consume(tENDCLASS);
12✔
3995

3996
   if (optional(tCOLON)) {
12✔
3997
      ident_t end_name = p_identifier();
10✔
3998
      if (name != end_name)
10✔
3999
         error_at(&state.last_loc, "'%s' does not match class name '%s'",
1✔
4000
                  istr(end_name), istr(name));
4001
   }
4002

4003
   vlog_set_loc(v, CURRENT_LOC);
12✔
4004
   vlog_symtab_put(symtab, v);
12✔
4005
   return v;
12✔
4006
}
4007

4008
static void p_block_item_declaration(vlog_node_t parent)
44✔
4009
{
4010
   // { attribute_instance } data_declaration
4011
   //   | { attribute_instance } local_parameter_declaration ;
4012
   //   | { attribute_instance } parameter_declaration ;
4013
   //   | { attribute_instance } overload_declaration
4014
   //   | { attribute_instance } let_declaration
4015

4016
   BEGIN("block item declaration");
88✔
4017

4018
   optional_attributes();
44✔
4019

4020
   switch (peek()) {
44✔
4021
   case tREG:
44✔
4022
   case tSTRUCT:
4023
   case tUNION:
4024
   case tTYPEDEF:
4025
   case tENUM:
4026
   case tSVINT:
4027
   case tINTEGER:
4028
   case tSVREAL:
4029
   case tSHORTREAL:
4030
   case tREALTIME:
4031
   case tBIT:
4032
   case tLOGIC:
4033
   case tSHORTINT:
4034
   case tTIME:
4035
      p_data_declaration(parent);
44✔
4036
      break;
44✔
UNCOV
4037
   default:
×
4038
      should_not_reach_here();
4039
   }
4040
}
44✔
4041

4042
static void p_package_or_generate_item_declaration(vlog_node_t parent)
4,312✔
4043
{
4044
   // net_declaration | data_declaration | task_declaration
4045
   //   | function_declaration | checker_declaration | dpi_import_export
4046
   //   | extern_constraint_declaration | class_declaration
4047
   //   | class_constructor_declaration | local_parameter_declaration ;
4048
   //   | parameter_declaration ; | covergroup_declaration
4049
   //   | overload_declaration | assertion_item_declaration | ;
4050

4051
   BEGIN("package or generate item declaration");
8,624✔
4052

4053
   switch (peek()) {
4,312✔
4054
   case tWIRE:
666✔
4055
   case tUWIRE:
4056
   case tSUPPLY0:
4057
   case tSUPPLY1:
4058
   case tTRI:
4059
   case tTRI0:
4060
   case tTRI1:
4061
   case tTRIAND:
4062
   case tTRIOR:
4063
   case tTRIREG:
4064
   case tWAND:
4065
   case tWOR:
4066
   case tINTERCONNECT:
4067
      p_net_declaration(parent);
666✔
4068
      break;
666✔
4069
   case tREG:
3,270✔
4070
   case tSTRUCT:
4071
   case tUNION:
4072
   case tTYPEDEF:
4073
   case tENUM:
4074
   case tSVINT:
4075
   case tINTEGER:
4076
   case tSVREAL:
4077
   case tSHORTREAL:
4078
   case tREALTIME:
4079
   case tTIME:
4080
   case tEVENT:
4081
   case tID:
4082
   case tVAR:
4083
   case tLOGIC:
4084
   case tBIT:
4085
   case tSHORTINT:
4086
   case tLONGINT:
4087
   case tBYTE:
4088
   case tSTRINGK:
4089
   case tIMPORT:
4090
      p_data_declaration(parent);
3,270✔
4091
      break;
3,270✔
4092
   case tTASK:
35✔
4093
      vlog_add_decl(parent, p_task_declaration());
35✔
4094
      break;
35✔
4095
   case tFUNCTION:
71✔
4096
      vlog_add_decl(parent, p_function_declaration());
71✔
4097
      break;
71✔
4098
   case tLOCALPARAM:
108✔
4099
      p_local_parameter_declaration(parent);
108✔
4100
      consume(tSEMI);
108✔
4101
      break;
108✔
4102
   case tPARAMETER:
150✔
4103
      p_parameter_declaration(parent);
150✔
4104
      consume(tSEMI);
150✔
4105
      break;
150✔
4106
   case tCLASS:
12✔
4107
   case tVIRTUAL:
4108
      vlog_add_decl(parent, p_class_declaration());
12✔
4109
      break;
12✔
UNCOV
4110
   default:
×
UNCOV
4111
      one_of(tWIRE, tUWIRE, tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND,
×
4112
             tTRIOR, tTRIREG, tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION,
4113
             tTYPEDEF, tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME,
4114
             tTIME, tEVENT, tID, tVAR, tLOGIC, tBIT, tSHORTINT, tLONGINT, tBYTE,
4115
             tSTRINGK, tIMPORT, tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER,
4116
             tCLASS, tVIRTUAL);
UNCOV
4117
      drop_tokens_until(&state, tSEMI);
×
UNCOV
4118
      break;
×
4119
   }
4120
}
4,312✔
4121

4122
static void p_list_of_genvar_identifiers(vlog_node_t mod, vlog_node_t dt)
14✔
4123
{
4124
   // genvar_identifier { , genvar_identifier }
4125

4126
   BEGIN("list of genvar identifiers");
28✔
4127

4128
   do {
14✔
4129
      vlog_node_t v = vlog_new(V_GENVAR_DECL);
14✔
4130
      vlog_set_ident(v, p_identifier());
14✔
4131
      vlog_set_type(v, dt);
14✔
4132
      vlog_set_loc(v, CURRENT_LOC);
14✔
4133

4134
      vlog_add_decl(mod, v);
14✔
4135

4136
      vlog_symtab_put(symtab, v);
14✔
4137
   } while (optional(tCOMMA));
14✔
4138
}
14✔
4139

4140
static void p_genvar_declaration(vlog_node_t mod)
14✔
4141
{
4142
   // genvar list_of_genvar_identifiers ;
4143

4144
   BEGIN("genvar declaration");
28✔
4145

4146
   consume(tGENVAR);
14✔
4147

4148
   vlog_node_t dt = make_integer_atom_type(DT_INTEGER);
14✔
4149
   vlog_set_flags(dt, VLOG_F_SIGNED);
14✔
4150

4151
   p_list_of_genvar_identifiers(mod, dt);
14✔
4152

4153
   consume(tSEMI);
14✔
4154
}
14✔
4155

4156
static void p_module_or_generate_item_declaration(vlog_node_t mod)
4,310✔
4157
{
4158
   // package_or_generate_item_declaration | genvar_declaration
4159
   //   | clocking_declaration | default clocking clocking_identifier ;
4160
   //   | default disable iff expression_or_dist ;
4161

4162
   BEGIN("module or generate item declaration");
8,620✔
4163

4164
   switch (peek()) {
4,310✔
4165
   case tGENVAR:
14✔
4166
      p_genvar_declaration(mod);
14✔
4167
      break;
14✔
4168
   default:
4,296✔
4169
      p_package_or_generate_item_declaration(mod);
4,296✔
4170
      break;
4,296✔
4171
   }
4172
}
4,310✔
4173

4174
static void p_generate_item(vlog_node_t parent)
134✔
4175
{
4176
   // module_or_generate_item | interface_or_generate_item
4177
   //   | checker_or_generate_item
4178

4179
   BEGIN("generate item");
268✔
4180

4181
   p_module_or_generate_item(parent);
134✔
4182
}
134✔
4183

4184
static vlog_node_t p_generate_block(void)
73✔
4185
{
4186
   // generate_item
4187
   //   | [ generate_block_identifier : ] begin [ : generate_block_identifier ]
4188
   //         { generate_item } end [ : generate_block_identifier ]
4189

4190
   BEGIN("generate block");
146✔
4191

4192
   vlog_node_t b = vlog_new(V_BLOCK);
73✔
4193

4194
   if (scan(tID, tBEGIN)) {
73✔
4195
      if (peek() == tID) {
56✔
4196
         vlog_set_ident(b, p_identifier());
1✔
4197
         consume(tCOLON);
1✔
4198
      }
4199

4200
      consume(tBEGIN);
56✔
4201

4202
      if (optional(tCOLON)) {
56✔
4203
         ident_t name = p_identifier();
28✔
4204
         if (vlog_has_ident(b))    // 1800-2023 section 9.3.5
28✔
4205
            parse_error(&state.last_loc, "cannot specify both a label and a "
1✔
4206
                        "name for the same block");
4207
         else
4208
            vlog_set_ident(b, name);
27✔
4209
      }
4210

4211
      vlog_symtab_push(symtab, b);
56✔
4212

4213
      while (not_at_token(tEND))
154✔
4214
         p_generate_item(b);
98✔
4215

4216
      vlog_symtab_pop(symtab);
56✔
4217

4218
      consume(tEND);
56✔
4219

4220
      if (optional(tCOLON)) {
56✔
4221
         ident_t name = p_identifier();
2✔
4222
         if (!vlog_has_ident(b))
2✔
4223
            parse_error(&state.last_loc, "block does not have a label");
1✔
4224
         else if (name != vlog_ident(b))
1✔
4225
            parse_error(&state.last_loc, "'%s' does not match label '%s'",
1✔
4226
                        istr(name), istr(vlog_ident(b)));
4227
      }
4228
   }
4229
   else
4230
      p_generate_item(b);
17✔
4231

4232
   if (!vlog_has_ident(b))
73✔
4233
      vlog_set_ident(b, default_label("genblk"));
45✔
4234

4235
   vlog_set_loc(b, CURRENT_LOC);
73✔
4236
   return b;
73✔
4237
}
4238

4239
static vlog_node_t p_if_generate_construct(void)
34✔
4240
{
4241
   // if ( constant_expression ) generate_block
4242
   //   { else if ( constant_expression ) generate_block }
4243
   //   [ else generate_block ]
4244

4245
   BEGIN("if generate construct");
68✔
4246

4247
   vlog_node_t v = vlog_new(V_IF_GENERATE);
34✔
4248

4249
   consume(tIF);
34✔
4250
   consume(tLPAREN);
34✔
4251

4252
   vlog_node_t c0 = vlog_new(V_COND);
34✔
4253
   vlog_set_value(c0, p_constant_expression());
34✔
4254

4255
   consume(tRPAREN);
34✔
4256

4257
   vlog_set_loc(c0, CURRENT_LOC);
34✔
4258
   vlog_add_stmt(c0, p_generate_block());
34✔
4259

4260
   vlog_add_cond(v, c0);
34✔
4261

4262
   while (optional(tELSE)) {
44✔
4263
      if (peek() == tIF) {
21✔
4264
         // else if ( constant_expression ) generate_block
4265
         consume(tIF);
10✔
4266
         consume(tLPAREN);
10✔
4267

4268
         vlog_node_t cn = vlog_new(V_COND);
10✔
4269
         vlog_set_value(cn, p_constant_expression());
10✔
4270

4271
         consume(tRPAREN);
10✔
4272

4273
         vlog_set_loc(cn, CURRENT_LOC);
10✔
4274
         vlog_add_stmt(cn, p_generate_block());
10✔
4275

4276
         vlog_add_cond(v, cn);
10✔
4277
      }
4278
      else {
4279
         // else generate_block (no condition = default branch)
4280
         vlog_node_t ce = vlog_new(V_COND);
11✔
4281
         vlog_set_loc(ce, &state.last_loc);
11✔
4282
         vlog_add_stmt(ce, p_generate_block());
11✔
4283

4284
         vlog_add_cond(v, ce);
11✔
4285
         break;
11✔
4286
      }
4287
   }
4288

4289
   vlog_set_loc(v, CURRENT_LOC);
34✔
4290
   return v;
34✔
4291
}
4292

4293
static vlog_node_t p_case_generate_construct(void)
1✔
4294
{
4295
   // case ( constant_expression )
4296
   //   case_generate_item { case_generate_item } endcase
4297
   //
4298
   // Lowered to V_IF_GENERATE with equality comparisons so the existing
4299
   // simplifier and elaborator handle it without a new node kind.
4300

4301
   BEGIN("case generate construct");
2✔
4302

4303
   consume(tCASE);
1✔
4304
   consume(tLPAREN);
1✔
4305

4306
   vlog_node_t selector = p_constant_expression();
1✔
4307

4308
   consume(tRPAREN);
1✔
4309

4310
   vlog_node_t v = vlog_new(V_IF_GENERATE);
1✔
4311

4312
   while (not_at_token(tENDCASE)) {
4✔
4313
      vlog_node_t cn = vlog_new(V_COND);
3✔
4314

4315
      if (optional(tDEFAULT)) {
3✔
4316
         // default branch: no condition (like else)
UNCOV
4317
         optional(tCOLON);
×
4318
      }
4319
      else {
4320
         // case_generate_item: constant_expression { , constant_expression }
4321
         //   : generate_block
4322
         // Build equality comparison: selector == label
4323
         // For multiple labels, OR them: (sel == l1) || (sel == l2)
4324
         vlog_node_t cond = NULL;
4325
         do {
3✔
4326
            vlog_node_t eq = vlog_new(V_BINARY);
3✔
4327
            vlog_set_subkind(eq, V_BINARY_LOG_EQ);
3✔
4328
            vlog_set_left(eq, selector);
3✔
4329
            vlog_set_right(eq, p_constant_expression());
3✔
4330
            vlog_set_loc(eq, CURRENT_LOC);
3✔
4331

4332
            if (cond == NULL) {
3✔
4333
               cond = eq;
4334
            }
4335
            else {
4336
               vlog_node_t lor = vlog_new(V_BINARY);
×
4337
               vlog_set_subkind(lor, V_BINARY_LOG_OR);
×
UNCOV
4338
               vlog_set_left(lor, cond);
×
UNCOV
4339
               vlog_set_right(lor, eq);
×
UNCOV
4340
               vlog_set_loc(lor, CURRENT_LOC);
×
UNCOV
4341
               cond = lor;
×
4342
            }
4343
         } while (optional(tCOMMA));
3✔
4344

4345
         consume(tCOLON);
3✔
4346
         vlog_set_value(cn, cond);
3✔
4347
      }
4348

4349
      vlog_set_loc(cn, CURRENT_LOC);
3✔
4350
      vlog_add_stmt(cn, p_generate_block());
3✔
4351
      vlog_add_cond(v, cn);
3✔
4352
   }
4353

4354
   consume(tENDCASE);
1✔
4355

4356
   vlog_set_loc(v, CURRENT_LOC);
1✔
4357
   return v;
1✔
4358
}
4359

4360
static vlog_node_t p_conditional_generate_construct(void)
35✔
4361
{
4362
   // if_generate_construct | case_generate_construct
4363

4364
   BEGIN("conditional generate construct");
70✔
4365

4366
   switch (peek()) {
35✔
4367
   case tIF:
34✔
4368
      return p_if_generate_construct();
34✔
4369
   case tCASE:
1✔
4370
      return p_case_generate_construct();
1✔
UNCOV
4371
   default:
×
4372
      should_not_reach_here();
4373
   }
4374
}
4375

4376
static vlog_node_t p_genvar_initialization(void)
15✔
4377
{
4378
   // [ genvar ] genvar_identifier = constant_expression
4379

4380
   BEGIN("genvar initialization");
30✔
4381

4382
   vlog_node_t v = vlog_new(V_FOR_INIT);
15✔
4383

4384
   vlog_node_t ref = vlog_new(V_REF);
15✔
4385
   vlog_set_ident(ref, p_identifier());
15✔
4386
   vlog_set_loc(ref, &state.last_loc);
15✔
4387

4388
   vlog_symtab_lookup(symtab, ref);
15✔
4389

4390
   consume(tEQ);
15✔
4391

4392
   vlog_node_t a = vlog_new(V_BASSIGN);
15✔
4393
   vlog_set_target(a, ref);
15✔
4394
   vlog_set_value(a, p_constant_expression());
15✔
4395
   vlog_set_loc(a, CURRENT_LOC);
15✔
4396

4397
   vlog_add_stmt(v, a);
15✔
4398

4399
   vlog_set_loc(v, CURRENT_LOC);
15✔
4400
   return v;
15✔
4401
}
4402

4403
static vlog_node_t p_genvar_iteration(void)
15✔
4404
{
4405
   // genvar_identifier assignment_operator genvar_expression
4406
   //   | inc_or_dec_operator genvar_identifier
4407
   //   | genvar_identifier inc_or_dec_operator
4408

4409
   BEGIN("genvar iteration");
30✔
4410

4411
   vlog_node_t v = vlog_new(V_FOR_STEP);
15✔
4412

4413
   vlog_node_t prefix = NULL;
15✔
4414
   if (scan(tPLUSPLUS, tMINUSMINUS)) {
15✔
4415
      prefix = vlog_new(V_PREFIX);
1✔
4416
      vlog_set_subkind(prefix, p_inc_or_dec_operator());
1✔
4417
   }
4418

4419
   vlog_node_t ref = vlog_new(V_REF);
15✔
4420
   vlog_set_ident(ref, p_identifier());
15✔
4421
   vlog_set_loc(ref, &state.last_loc);
15✔
4422

4423
   vlog_symtab_lookup(symtab, ref);
15✔
4424

4425
   if (prefix != NULL) {
15✔
4426
      vlog_set_target(prefix, ref);
1✔
4427

4428
      vlog_add_stmt(v, prefix);
1✔
4429
   }
4430
   else if (optional(tEQ)) {
14✔
4431
      vlog_node_t a = vlog_new(V_BASSIGN);
13✔
4432
      vlog_set_target(a, ref);
13✔
4433
      vlog_set_value(a, p_constant_expression());
13✔
4434

4435
      vlog_add_stmt(v, a);
13✔
4436
   }
4437
   else {
4438
      vlog_node_t a = vlog_new(V_POSTFIX);
1✔
4439
      vlog_set_subkind(a, p_inc_or_dec_operator());
1✔
4440
      vlog_set_target(a, ref);
1✔
4441

4442
      vlog_add_stmt(v, a);
1✔
4443
   }
4444

4445
   vlog_set_loc(v, CURRENT_LOC);
15✔
4446
   return v;
15✔
4447
}
4448

4449
static vlog_node_t p_loop_generate_construct(void)
15✔
4450
{
4451
   // for ( genvar_initialization ; genvar_expression ; genvar_iteration )
4452
   //   generate_block
4453

4454
   BEGIN("loop generate construct");
30✔
4455

4456
   consume(tFOR);
15✔
4457
   consume(tLPAREN);
15✔
4458

4459
   vlog_node_t v = vlog_new(V_FOR_GENERATE);
15✔
4460

4461
   vlog_symtab_push(symtab, v);
15✔
4462

4463
   vlog_set_left(v, p_genvar_initialization());
15✔
4464

4465
   consume(tSEMI);
15✔
4466

4467
   vlog_set_value(v, p_constant_expression());
15✔
4468

4469
   consume(tSEMI);
15✔
4470

4471
   vlog_set_right(v, p_genvar_iteration());
15✔
4472

4473
   consume(tRPAREN);
15✔
4474

4475
   vlog_add_stmt(v, p_generate_block());
15✔
4476

4477
   vlog_symtab_pop(symtab);
15✔
4478

4479
   vlog_set_loc(v, CURRENT_LOC);
15✔
4480
   return v;
15✔
4481
}
4482

4483
static void p_module_common_item(vlog_node_t mod)
5,753✔
4484
{
4485
   // module_or_generate_item_declaration
4486
   //   | interface_instantiation | program_instantiation
4487
   //   | assertion_item | bind_directive | continuous_assign
4488
   //   | net_alias | initial_construct | final_construct
4489
   //   | always_construct | loop_generate_construct
4490
   //   | conditional_generate_construct | elaboration_system_task
4491

4492
   BEGIN("module common item");
11,506✔
4493

4494
   switch (peek()) {
5,753✔
4495
   case tALWAYS:
302✔
4496
   case tALWAYSCOMB:
4497
   case tALWAYSFF:
4498
   case tALWAYSLATCH:
4499
      vlog_add_stmt(mod, p_always_construct());
302✔
4500
      break;
302✔
4501
   case tINITIAL:
633✔
4502
      vlog_add_stmt(mod, p_initial_construct());
633✔
4503
      break;
633✔
4504
   case tWIRE:
4,293✔
4505
   case tUWIRE:
4506
   case tSUPPLY0:
4507
   case tSUPPLY1:
4508
   case tTRI:
4509
   case tTRI0:
4510
   case tTRI1:
4511
   case tTRIAND:
4512
   case tTRIOR:
4513
   case tTRIREG:
4514
   case tWAND:
4515
   case tWOR:
4516
   case tINTERCONNECT:
4517
   case tREG:
4518
   case tSTRUCT:
4519
   case tUNION:
4520
   case tTYPEDEF:
4521
   case tENUM:
4522
   case tSVINT:
4523
   case tINTEGER:
4524
   case tSVREAL:
4525
   case tSHORTREAL:
4526
   case tREALTIME:
4527
   case tTIME:
4528
   case tTASK:
4529
   case tFUNCTION:
4530
   case tLOCALPARAM:
4531
   case tPARAMETER:
4532
   case tEVENT:
4533
   case tID:
4534
   case tGENVAR:
4535
   case tVAR:
4536
   case tLOGIC:
4537
   case tBIT:
4538
   case tSHORTINT:
4539
   case tLONGINT:
4540
   case tBYTE:
4541
   case tSTRINGK:
4542
   case tIMPORT:
4543
      p_module_or_generate_item_declaration(mod);
4,293✔
4544
      break;
4,293✔
4545
   case tASSIGN:
475✔
4546
      p_continuous_assign(mod);
475✔
4547
      break;
475✔
4548
   case tFOR:
15✔
4549
      vlog_add_stmt(mod, p_loop_generate_construct());
15✔
4550
      break;
15✔
4551
   case tIF:
35✔
4552
   case tCASE:
4553
      vlog_add_stmt(mod, p_conditional_generate_construct());
35✔
4554
      break;
35✔
UNCOV
4555
   default:
×
UNCOV
4556
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
×
4557
             tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
4558
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM,
4559
             tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTIME, tTASK,
4560
             tFUNCTION, tPARAMETER, tLOCALPARAM, tEVENT, tID, tGENVAR, tVAR,
4561
             tLOGIC, tBIT, tSHORTINT, tLONGINT, tBYTE, tSTRINGK, tIMPORT,
4562
             tASSIGN, tFOR, tIF);
UNCOV
4563
      drop_tokens_until(&state, tSEMI);
×
4564
   }
4565
}
5,753✔
4566

4567
static vlog_strength_t p_strength0(void)
58✔
4568
{
4569
   // supply0 | strong0 | pull0 | weak0
4570

4571
   BEGIN("strength0");
116✔
4572

4573
   switch (one_of(tSUPPLY0, tSTRONG0, tPULL0, tWEAK0)) {
58✔
4574
   default:
4575
   case tSUPPLY0: return V_STRENGTH_SUPPLY;
4576
   case tSTRONG0: return V_STRENGTH_STRONG;
4577
   case tPULL0:   return V_STRENGTH_PULL;
4578
   case tWEAK0:   return V_STRENGTH_WEAK;
4579
   }
4580
}
4581

4582
static vlog_strength_t p_strength1(void)
60✔
4583
{
4584
   // supply1 | strong1 | pull1 | weak1
4585

4586
   BEGIN("strength1");
120✔
4587

4588
   switch (one_of(tSUPPLY1, tSTRONG1, tPULL1, tWEAK1)) {
60✔
4589
   default:
4590
   case tSUPPLY1: return V_STRENGTH_SUPPLY;
4591
   case tSTRONG1: return V_STRENGTH_STRONG;
4592
   case tPULL1:   return V_STRENGTH_PULL;
4593
   case tWEAK1:   return V_STRENGTH_WEAK;
4594
   }
4595
}
4596

4597
static vlog_node_t p_pulldown_strength(void)
2✔
4598
{
4599
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength0 )
4600

4601
   BEGIN("pulldown strength");
4✔
4602

4603
   consume(tLPAREN);
2✔
4604

4605
   vlog_strength_t s0, s1;
2✔
4606
   switch (peek()) {
2✔
4607
   case tSUPPLY1:
×
4608
   case tSTRONG1:
4609
   case tPULL1:
4610
   case tWEAK1:
UNCOV
4611
      s1 = p_strength1();
×
UNCOV
4612
      consume(tCOMMA);
×
UNCOV
4613
      s0 = p_strength0();
×
4614
      break;
×
4615
   default:
2✔
4616
      s0 = s1 = p_strength0();
2✔
4617
      if (optional(tCOMMA))
2✔
UNCOV
4618
         s1 = p_strength1();
×
4619
      break;
4620
   }
4621

4622
   consume(tRPAREN);
2✔
4623

4624
   vlog_node_t v = vlog_new(V_STRENGTH);
2✔
4625
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
2✔
4626
   vlog_set_loc(v, CURRENT_LOC);
2✔
4627
   return v;
2✔
4628
}
4629

4630
static vlog_node_t p_pullup_strength(void)
7✔
4631
{
4632
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength1 )
4633

4634
   BEGIN("pullup strength");
14✔
4635

4636
   consume(tLPAREN);
7✔
4637

4638
   vlog_strength_t s0, s1;
7✔
4639
   switch (peek()) {
7✔
4640
   case tSUPPLY0:
1✔
4641
   case tSTRONG0:
4642
   case tPULL0:
4643
   case tWEAK0:
4644
      s0 = p_strength0();
1✔
4645
      consume(tCOMMA);
1✔
4646
      s1 = p_strength1();
1✔
4647
      break;
1✔
4648
   default:
6✔
4649
      s1 = s0 = p_strength1();
6✔
4650
      if (optional(tCOMMA))
6✔
4651
         s0 = p_strength0();
1✔
4652
      break;
4653
   }
4654

4655
   consume(tRPAREN);
7✔
4656

4657
   vlog_node_t v = vlog_new(V_STRENGTH);
7✔
4658
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
7✔
4659
   vlog_set_loc(v, CURRENT_LOC);
7✔
4660
   return v;
7✔
4661
}
4662

4663
static vlog_node_t p_pull_gate_instance(vlog_gate_kind_t kind, vlog_node_t st)
22✔
4664
{
4665
   // [ name_of_instance ] ( output_terminal )
4666

4667
   BEGIN("pull gate instance");
44✔
4668

4669
   vlog_node_t v = vlog_new(V_GATE_INST);
22✔
4670
   vlog_set_subkind(v, kind);
22✔
4671
   vlog_add_param(v, st);
22✔
4672

4673
   if (peek() == tID) {
22✔
4674
      vlog_set_ident(v, p_identifier());
7✔
4675
      vlog_set_loc(v, &state.last_loc);
7✔
4676
      vlog_symtab_put(symtab, v);
7✔
4677
   }
4678
   else
4679
      vlog_set_ident(v, default_label("gate"));
15✔
4680

4681
   consume(tLPAREN);
22✔
4682

4683
   vlog_symtab_set_implicit(symtab, implicit_kind);
22✔
4684

4685
   vlog_set_target(v, p_net_lvalue());
22✔
4686

4687
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
22✔
4688

4689
   consume(tRPAREN);
22✔
4690

4691
   vlog_set_loc(v, CURRENT_LOC);
22✔
4692
   return v;
22✔
4693
}
4694

4695
static vlog_node_t p_n_terminal_gate_instance(vlog_gate_kind_t kind,
35✔
4696
                                              vlog_node_t st)
4697
{
4698
   // [ name_of_instance ] ( output_terminal , input_terminal
4699
   //     { , input_terminal } )
4700

4701
   BEGIN("N-terminal gate instance");
70✔
4702

4703
   vlog_node_t v = vlog_new(V_GATE_INST);
35✔
4704
   vlog_set_subkind(v, kind);
35✔
4705

4706
   if (peek() == tID) {
35✔
4707
      vlog_set_ident(v, p_identifier());
5✔
4708
      vlog_set_loc(v, &state.last_loc);
5✔
4709
      vlog_symtab_put(symtab, v);
5✔
4710
   }
4711
   else
4712
      vlog_set_ident(v, default_label("gate"));
30✔
4713

4714
   consume(tLPAREN);
35✔
4715

4716
   vlog_symtab_set_implicit(symtab, implicit_kind);
35✔
4717

4718
   vlog_set_target(v, p_net_lvalue());
35✔
4719

4720
   consume(tCOMMA);
35✔
4721

4722
   do {
56✔
4723
      vlog_add_param(v, p_expression());
56✔
4724
   } while (optional(tCOMMA));
56✔
4725

4726
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
35✔
4727

4728
   consume(tRPAREN);
35✔
4729

4730
   vlog_set_loc(v, CURRENT_LOC);
35✔
4731
   return v;
35✔
4732
}
4733

4734
static vlog_node_t p_enable_gate_instance(vlog_gate_kind_t kind)
1✔
4735
{
4736
   // [ name_of_instance ] ( output_terminal , input_terminal ,
4737
   //     enable_terminal )
4738

4739
   BEGIN("enable gate instance");
2✔
4740

4741
   vlog_node_t v = vlog_new(V_GATE_INST);
1✔
4742
   vlog_set_subkind(v, kind);
1✔
4743

4744
   if (peek() == tID) {
1✔
UNCOV
4745
      vlog_set_ident(v, p_identifier());
×
UNCOV
4746
      vlog_set_loc(v, &state.last_loc);
×
UNCOV
4747
      vlog_symtab_put(symtab, v);
×
4748
   }
4749
   else
4750
      vlog_set_ident(v, default_label("gate"));
1✔
4751

4752
   consume(tLPAREN);
1✔
4753

4754
   vlog_symtab_set_implicit(symtab, implicit_kind);
1✔
4755

4756
   vlog_set_target(v, p_net_lvalue());
1✔
4757

4758
   consume(tCOMMA);
1✔
4759

4760
   vlog_add_param(v, p_expression());
1✔
4761

4762
   consume(tCOMMA);
1✔
4763

4764
   vlog_add_param(v, p_expression());
1✔
4765

4766
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
1✔
4767

4768
   consume(tRPAREN);
1✔
4769

4770
   vlog_set_loc(v, CURRENT_LOC);
1✔
4771
   return v;
1✔
4772
}
4773

4774
static vlog_node_t p_pass_switch_instance(vlog_gate_kind_t kind)
1✔
4775
{
4776
   // [ name_of_instance ] ( inout_terminal , inout_terminal )
4777

4778
   BEGIN("pass switch instance");
2✔
4779

4780
   vlog_node_t v = vlog_new(V_GATE_INST);
1✔
4781
   vlog_set_subkind(v, kind);
1✔
4782

4783
   if (peek() == tID) {
1✔
UNCOV
4784
      vlog_set_ident(v, p_identifier());
×
UNCOV
4785
      vlog_set_loc(v, &state.last_loc);
×
UNCOV
4786
      vlog_symtab_put(symtab, v);
×
4787
   }
4788
   else
4789
      vlog_set_ident(v, default_label("gate"));
1✔
4790

4791
   consume(tLPAREN);
1✔
4792

4793
   vlog_symtab_set_implicit(symtab, implicit_kind);
1✔
4794

4795
   vlog_set_target(v, p_net_lvalue());
1✔
4796

4797
   consume(tCOMMA);
1✔
4798

4799
   vlog_add_param(v, p_net_lvalue());
1✔
4800

4801
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
1✔
4802

4803
   consume(tRPAREN);
1✔
4804

4805
   vlog_set_loc(v, CURRENT_LOC);
1✔
4806
   return v;
1✔
4807
}
4808

4809
static vlog_node_t p_pass_enable_switch_instance(vlog_gate_kind_t kind)
1✔
4810
{
4811
   // [ name_of_instance ] ( inout_terminal , inout_terminal ,
4812
   //     enable_terminal )
4813

4814
   BEGIN("pass enable switch instance");
2✔
4815

4816
   vlog_node_t v = vlog_new(V_GATE_INST);
1✔
4817
   vlog_set_subkind(v, kind);
1✔
4818

4819
   if (peek() == tID) {
1✔
UNCOV
4820
      vlog_set_ident(v, p_identifier());
×
UNCOV
4821
      vlog_set_loc(v, &state.last_loc);
×
UNCOV
4822
      vlog_symtab_put(symtab, v);
×
4823
   }
4824
   else
4825
      vlog_set_ident(v, default_label("gate"));
1✔
4826

4827
   consume(tLPAREN);
1✔
4828

4829
   vlog_symtab_set_implicit(symtab, implicit_kind);
1✔
4830

4831
   vlog_set_target(v, p_net_lvalue());
1✔
4832

4833
   consume(tCOMMA);
1✔
4834

4835
   vlog_add_param(v, p_net_lvalue());
1✔
4836

4837
   consume(tCOMMA);
1✔
4838

4839
   vlog_add_param(v, p_expression());
1✔
4840

4841
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
1✔
4842

4843
   consume(tRPAREN);
1✔
4844

4845
   vlog_set_loc(v, CURRENT_LOC);
1✔
4846
   return v;
1✔
4847
}
4848

4849
static void p_gate_instantiation(vlog_node_t mod)
60✔
4850
{
4851
   // cmos_switchtype [ delay3 ] cmos_switch_instance
4852
   //     { , cmos_switch_instance } ;
4853
   //  | enable_gatetype [ drive_strength ] [ delay3 ]
4854
   //     enable_gate_instance { , enable_gate_instance } ;
4855
   //  | mos_switchtype [ delay3 ] mos_switch_instance
4856
   //     { , mos_switch_instance } ;
4857
   //  | n_input_gatetype [ drive_strength ] [ delay2 ] n_input_gate_instance
4858
   //     { , n_input_gate_instance } ;
4859
   //  | n_output_gatetype [ drive_strength ] [ delay2 ] n_output_gate_instance
4860
   //     { , n_output_gate_instance } ;
4861
   //  | pass_en_switchtype [ delay2 ] pass_enable_switch_instance
4862
   //     { , pass_enable_switch_instance } ;
4863
   //  | pass_switchtype pass_switch_instance { , pass_switch_instance } ;
4864
   //  | pulldown [ pulldown_strength ] pull_gate_instance
4865
   //     { , pull_gate_instance } ;
4866
   //  | pullup [ pullup_strength ] pull_gate_instance
4867
   //     { , pull_gate_instance } ;
4868

4869
   BEGIN("gate instantiation");
120✔
4870

4871
   token_t token = one_of(tPULLDOWN, tPULLUP, tAND, tNAND, tOR, tNOR,
60✔
4872
                          tXOR, tXNOR, tNOT, tBUF, tBUFIF0, tBUFIF1,
4873
                          tNOTIF0, tNOTIF1, tTRAN, tRTRAN, tTRANIF0, tTRANIF1,
4874
                          tRTRANIF0, tRTRANIF1);
4875

4876
   switch (token) {
60✔
4877
   case tPULLDOWN:
8✔
4878
      {
4879
         vlog_node_t st;
8✔
4880
         if (peek() == tLPAREN && peek_nth(2) != tID)
8✔
4881
            st = p_pulldown_strength();
2✔
4882
         else {
4883
            st = vlog_new(V_STRENGTH);
6✔
4884
            vlog_set_subkind(st, ST_PULLUP);
6✔
4885
         }
4886

4887
         do {
8✔
4888
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLDOWN, st);
8✔
4889
            vlog_add_stmt(mod, g);
8✔
4890
         } while (optional(tCOMMA));
8✔
4891
      }
4892
      break;
4893

4894
   case tPULLUP:
14✔
4895
      {
4896
         vlog_node_t st;
14✔
4897
         if (peek() == tLPAREN && peek_nth(2) != tID)
14✔
4898
            st = p_pullup_strength();
7✔
4899
         else {
4900
            st = vlog_new(V_STRENGTH);
7✔
4901
            vlog_set_subkind(st, ST_PULLUP);
7✔
4902
         }
4903

4904
         do {
14✔
4905
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLUP, st);
14✔
4906
            vlog_add_stmt(mod, g);
14✔
4907
         } while (optional(tCOMMA));
14✔
4908
      }
4909
      break;
4910

4911
   case tAND:
35✔
4912
   case tNAND:
4913
   case tOR:
4914
   case tNOR:
4915
   case tXOR:
4916
   case tXNOR:
4917
   case tNOT:
4918
   case tBUF:
4919
      {
4920
         vlog_node_t st;
35✔
4921
         if (peek() == tLPAREN && peek_nth(2) != tID)
35✔
4922
            st = p_drive_strength();
1✔
4923
         else {
4924
            st = vlog_new(V_STRENGTH);
34✔
4925
            vlog_set_subkind(st, ST_STRONG);
34✔
4926
         }
4927

4928
         const vlog_gate_kind_t kind = get_gate_kind(token);
35✔
4929

4930
         if (peek() == tHASH)
35✔
4931
            p_delay2();
2✔
4932

4933
         do {
35✔
4934
            vlog_add_stmt(mod, p_n_terminal_gate_instance(kind, st));
35✔
4935
         } while (optional(tCOMMA));
35✔
4936
      }
4937
      break;
4938

4939
   case tBUFIF0:
1✔
4940
   case tBUFIF1:
4941
   case tNOTIF0:
4942
   case tNOTIF1:
4943
      {
4944
         vlog_node_t st;
1✔
4945
         if (peek() == tLPAREN && peek_nth(2) != tID)
1✔
4946
            st = p_drive_strength();
1✔
4947
         else {
UNCOV
4948
            st = vlog_new(V_STRENGTH);
×
4949
            vlog_set_subkind(st, ST_STRONG);
×
4950
         }
4951

4952
         if (peek() == tHASH)
1✔
UNCOV
4953
            p_delay3();
×
4954

4955
         const vlog_gate_kind_t kind = get_gate_kind(token);
1✔
4956

4957
         do {
1✔
4958
            vlog_add_stmt(mod, p_enable_gate_instance(kind));
1✔
4959
         } while (optional(tCOMMA));
1✔
4960
      }
4961
      break;
4962

4963
   case tTRAN:
1✔
4964
   case tRTRAN:
4965
      {
4966
         const vlog_gate_kind_t kind = get_gate_kind(token);
1✔
4967

4968
         do {
1✔
4969
            vlog_add_stmt(mod, p_pass_switch_instance(kind));
1✔
4970
         } while (optional(tCOMMA));
1✔
4971
      }
4972
      break;
4973

4974
   case tTRANIF0:
1✔
4975
   case tTRANIF1:
4976
   case tRTRANIF0:
4977
   case tRTRANIF1:
4978
      {
4979
         if (peek() == tHASH)
1✔
UNCOV
4980
            p_delay2();
×
4981

4982
         const vlog_gate_kind_t kind = get_gate_kind(token);
1✔
4983

4984
         do {
1✔
4985
            vlog_add_stmt(mod, p_pass_enable_switch_instance(kind));
1✔
4986
         } while (optional(tCOMMA));
1✔
4987
      }
4988
      break;
4989

4990
   default:
4991
      break;
4992
   }
4993

4994
   consume(tSEMI);
60✔
4995
}
60✔
4996

4997
static vlog_node_t p_module_path_expression(void)
4✔
4998
{
4999
   // module_path_primary
5000
   //   | unary_module_path_operator { attribute_instance } module_path_primary
5001
   //   | module_path_expression binary_module_path_operator
5002
   //      { attribute_instance } module_path_expression
5003
   //   | module_path_conditional_expression
5004

5005
   BEGIN("module path expression");
8✔
5006

5007
   // TODO: sem should check valid subset
5008
   return p_expression();
4✔
5009
}
5010

5011
static void p_path_delay_expression(void)
22✔
5012
{
5013
   // constant_expression
5014
   //   | constant_expression : constant_expression : constant_expression
5015

5016
   BEGIN("path delay expression");
44✔
5017

5018
   (void)p_constant_expression();
22✔
5019
}
22✔
5020

5021
static void p_list_of_path_delay_expressions(void)
18✔
5022
{
5023
   // path_delay_expression { , path_delay_expression }
5024

5025
   BEGIN("list of path delay expressions");
36✔
5026

5027
   do {
22✔
5028
      p_path_delay_expression();
22✔
5029
   } while (optional(tCOMMA));
22✔
5030
}
18✔
5031

5032
static void p_path_delay_value(void)
18✔
5033
{
5034
   // list_of_path_delay_expressions | ( list_of_path_delay_expressions )
5035

5036
   BEGIN("path delay value");
36✔
5037

5038
   if (optional(tLPAREN)) {
18✔
5039
      p_list_of_path_delay_expressions();
4✔
5040
      consume(tRPAREN);
4✔
5041
   }
5042
   else
5043
      p_list_of_path_delay_expressions();
14✔
5044
}
18✔
5045

5046
static vlog_node_t p_specify_terminal_descriptor(void)
76✔
5047
{
5048
   // identifier [ [ constant_range_expression ] ]
5049

5050
   BEGIN("specify terminal descriptor");
152✔
5051

5052
   vlog_node_t v = vlog_new(V_REF);
76✔
5053
   vlog_set_ident(v, p_identifier());
76✔
5054
   vlog_set_loc(v, CURRENT_LOC);
76✔
5055

5056
   if (optional(tLSQUARE)) {
76✔
5057
      (void)p_constant_range_expression();
2✔
5058
      consume(tRSQUARE);
2✔
5059
   }
5060

5061
   return v;
76✔
5062
}
5063

5064
static void p_list_of_path_inputs(vlog_node_t v, vlog_node_t head)
8✔
5065
{
5066
   // specify_input_terminal_descriptor { , specify_input_terminal_descriptor }
5067

5068
   BEGIN_WITH_HEAD("list of path inputs", head);
16✔
5069

5070
   while (optional(tCOMMA))
15✔
5071
      (void)p_specify_terminal_descriptor();
7✔
5072
}
8✔
5073

5074
static void p_list_of_path_outputs(vlog_node_t v)
8✔
5075
{
5076
   // specify_output_terminal_descriptor
5077
   //     { , specify_output_terminal_descriptor }
5078

5079
   BEGIN("list of path outputs");
16✔
5080

5081
   do {
17✔
5082
      (void)p_specify_terminal_descriptor();
17✔
5083
   } while (optional(tCOMMA));
17✔
5084
}
8✔
5085

5086
static void p_polarity_operator(void)
9✔
5087
{
5088
   // + | -
5089

5090
   BEGIN("polarity operator");
18✔
5091

5092
   (void)one_of(tPLUS, tMINUS);
9✔
5093
}
9✔
5094

5095
static vlog_node_t p_parallel_path_description(vlog_node_t head)
8✔
5096
{
5097
   // ( specify_input_terminal_descriptor [ polarity_operator ]
5098
   //     => specify_output_terminal_descriptor )
5099

5100
   EXTEND("parallel path description");
16✔
5101

5102
   if (scan(tPLUS, tMINUS))
8✔
5103
      (void)p_polarity_operator();
3✔
5104

5105
   consume(tASSOC);
8✔
5106

5107
   (void)p_specify_terminal_descriptor();
8✔
5108

5109
   consume(tRPAREN);
8✔
5110
   return NULL;
8✔
5111
}
5112

5113
static vlog_node_t p_full_path_description(vlog_node_t head)
3✔
5114
{
5115
   // ( list_of_path_inputs [ polarity_operator ] *> list_of_path_outputs )
5116

5117
   EXTEND("full path description");
6✔
5118

5119
   p_list_of_path_inputs(NULL, head);
3✔
5120

5121
   if (scan(tPLUS, tMINUS))
3✔
5122
      (void)p_polarity_operator();
3✔
5123

5124
   consume(tTIMESGT);
3✔
5125

5126
   p_list_of_path_outputs(NULL);
3✔
5127

5128
   consume(tRPAREN);
3✔
5129
   return NULL;
3✔
5130
}
5131

5132
static vlog_node_t p_simple_path_declaration(void)
11✔
5133
{
5134
   // parallel_path_description = path_delay_value
5135
   //   | full_path_description = path_delay_value
5136

5137
   BEGIN("simple path declaration");
22✔
5138

5139
   // Parse up to the first terminal descriptor to determine which
5140
   // production to use
5141

5142
   consume(tLPAREN);
11✔
5143

5144
   vlog_node_t head = p_specify_terminal_descriptor();
11✔
5145

5146
   if (scan(tCOMMA, tTIMESGT) || peek_nth(2) == tTIMESGT)
11✔
5147
      (void)p_full_path_description(head);
3✔
5148
   else
5149
      (void)p_parallel_path_description(head);
8✔
5150

5151
   consume(tEQ);
11✔
5152

5153
   (void)p_path_delay_value();
11✔
5154

5155
   return NULL;
11✔
5156
}
5157

5158
static void p_edge_identifier(void)
7✔
5159
{
5160
   // posedge | negedge | edge
5161

5162
   BEGIN("edge identifier");
14✔
5163

5164
   one_of(tPOSEDGE, tNEGEDGE, tEDGE);
7✔
5165
}
7✔
5166

5167
static vlog_node_t p_parallel_edge_sensitive_path_description(vlog_node_t head)
2✔
5168
{
5169
   // ( [ edge_identifier ] specify_input_terminal_descriptor
5170
   //     [ polarity_operator ] => ( specify_output_terminal_descriptor
5171
   //     [ polarity_operator ] : data_source_expression ) )
5172

5173
   EXTEND("parallel edge sensitive path description");
4✔
5174

5175
   if (scan(tPLUS, tMINUS))
2✔
UNCOV
5176
      (void)p_polarity_operator();
×
5177

5178
   consume(tASSOC);
2✔
5179

5180
   consume(tLPAREN);
2✔
5181

5182
   (void)p_specify_terminal_descriptor();
2✔
5183

5184
   if (scan(tPLUS, tMINUS)) {
2✔
UNCOV
5185
      (void)p_polarity_operator();
×
UNCOV
5186
      consume(tCOLON);
×
5187
   }
5188
   else if (scan(tINDEXPOS, tINDEXNEG))
2✔
5189
      consume(peek());  // Lexing ambiguity with +: and -:
1✔
5190
   else
5191
      consume(tCOLON);
1✔
5192

5193
   (void)p_expression();
2✔
5194

5195
   consume(tRPAREN);
2✔
5196
   consume(tRPAREN);
2✔
5197
   return NULL;
2✔
5198
}
5199

5200
static vlog_node_t p_full_edge_sensitive_path_description(vlog_node_t head)
5✔
5201
{
5202
   // ( [ edge_identifier ] list_of_path_inputs [ polarity_operator ] *>
5203
   //     ( list_of_path_outputs [ polarity_operator ]
5204
   //     : data_source_expression ) )
5205

5206
   EXTEND("full edge sensitive path description");
10✔
5207

5208
   p_list_of_path_inputs(NULL, head);
5✔
5209

5210
   if (scan(tPLUS, tMINUS))
5✔
5211
      (void)p_polarity_operator();
3✔
5212

5213
   consume(tTIMESGT);
5✔
5214

5215
   consume(tLPAREN);
5✔
5216

5217
   p_list_of_path_outputs(NULL);
5✔
5218

5219
   if (scan(tPLUS, tMINUS)) {
5✔
UNCOV
5220
      (void)p_polarity_operator();
×
UNCOV
5221
      consume(tCOLON);
×
5222
   }
5223
   else if (scan(tINDEXPOS, tINDEXNEG))
5✔
5224
      consume(peek());  // Lexing ambiguity with +: and -:
2✔
5225
   else
5226
      consume(tCOLON);
3✔
5227

5228
   (void)p_expression();
5✔
5229

5230
   consume(tRPAREN);
5✔
5231
   consume(tRPAREN);
5✔
5232
   return NULL;
5✔
5233
}
5234

5235
static vlog_node_t p_edge_sensitive_path_declaration(void)
7✔
5236
{
5237
   // parallel_edge_sensitive_path_description = path_delay_value
5238
   //   | full_edge_sensitive_path_description = path_delay_value
5239

5240
   BEGIN("edge sensitive path declaration");
14✔
5241

5242
   // Parse up to the first terminal descriptor to determine which
5243
   // production to use
5244

5245
   consume(tLPAREN);
7✔
5246

5247
   if (scan(tEDGE, tPOSEDGE, tNEGEDGE))
7✔
5248
      p_edge_identifier();
7✔
5249

5250
   vlog_node_t head = p_specify_terminal_descriptor();
7✔
5251

5252
   if (scan(tCOMMA, tTIMESGT) || peek_nth(2) == tTIMESGT)
7✔
5253
      (void)p_full_edge_sensitive_path_description(head);
5✔
5254
   else
5255
      (void)p_parallel_edge_sensitive_path_description(head);
2✔
5256

5257
   consume(tEQ);
7✔
5258

5259
   (void)p_path_delay_value();
7✔
5260

5261
   return NULL;
7✔
5262
}
5263

5264
static vlog_node_t p_state_dependent_path_declaration(void)
6✔
5265
{
5266
   // if ( module_path_expression ) simple_path_declaration
5267
   //   | if ( module_path_expression ) edge_sensitive_path_declaration
5268
   //   | ifnone simple_path_declaration
5269

5270
   BEGIN("state dependent path declaration");
12✔
5271

5272
   switch (one_of(tIF, tIFNONE)) {
6✔
5273
   case tIF:
4✔
5274
      consume(tLPAREN);
4✔
5275
      (void)p_module_path_expression();
4✔
5276
      consume(tRPAREN);
4✔
5277
      break;
4✔
5278
   case tIFNONE:
5279
      break;
5280
   }
5281

5282
   if (peek_nth(2) == tID)
6✔
5283
      (void)p_simple_path_declaration();
2✔
5284
   else {
5285
      // This is invalid for ifnone according to the grammar but is
5286
      // accepted by some simulators and seen in the wild
5287
      (void)p_edge_sensitive_path_declaration();
4✔
5288
   }
5289

5290
   return NULL;
6✔
5291
}
5292

5293
static vlog_node_t p_path_declaration(void)
18✔
5294
{
5295
   // simple_path_declaration ;
5296
   //  | edge_sensitive_path_declaration ;
5297
   //  | state_dependent_path_declaration ;
5298

5299
   BEGIN("path declaration");
36✔
5300

5301
   switch (peek()) {
18✔
5302
   case tIF:
6✔
5303
   case tIFNONE:
5304
      (void)p_state_dependent_path_declaration();
6✔
5305
      break;
6✔
5306
   case tLPAREN:
12✔
5307
      switch (peek_nth(2)) {
12✔
5308
      case tEDGE:
3✔
5309
      case tNEGEDGE:
5310
      case tPOSEDGE:
5311
         (void)p_edge_sensitive_path_declaration();
3✔
5312
         break;
3✔
5313
      default:
9✔
5314
         (void)p_simple_path_declaration();
9✔
5315
         break;
9✔
5316
      }
5317
      break;
UNCOV
5318
   default:
×
UNCOV
5319
      one_of(tIF, tIFNONE);
×
5320
   }
5321

5322
   consume(tSEMI);
18✔
5323
   return NULL;
18✔
5324
}
5325

5326
static void p_timing_check_event_control(void)
8✔
5327
{
5328
   // posedge | negedge | edge | edge_control_specifier
5329

5330
   BEGIN("timing check event control");
16✔
5331

5332
   one_of(tPOSEDGE, tNEGEDGE, tEDGE);
8✔
5333
}
8✔
5334

5335
static void p_scalar_timing_check_condition(void)
4✔
5336
{
5337
   //    expression
5338
   // | ~ expression
5339
   // | expression == scalar_constant
5340
   // | expression === scalar_constant
5341
   // | expression != scalar_constant
5342
   // | expression !== scalar_constant
5343

5344
   BEGIN("scalar timing check condition")
8✔
5345

5346
   p_expression();
4✔
5347
}
4✔
5348

5349
static void p_timing_check_condition(void)
4✔
5350
{
5351
   //     scalar_timing_check_condition
5352
   // | ( scalar_timing_check_condition )
5353

5354
   BEGIN("timing check condition");
8✔
5355

5356
   if (optional(tLPAREN)) {
4✔
5357
      p_scalar_timing_check_condition();
1✔
5358
      consume(tRPAREN);
1✔
5359
   }
5360
   else
5361
      p_scalar_timing_check_condition();
3✔
5362
}
4✔
5363

5364
static vlog_node_t p_timing_check_event(void)
20✔
5365
{
5366
   // [ timing_check_event_control ] specify_terminal_descriptor
5367
   //    [ &&& timing_check_condition ]
5368

5369
   BEGIN("timing check event");
40✔
5370

5371
   if (scan(tEDGE, tPOSEDGE, tNEGEDGE))
20✔
5372
      p_timing_check_event_control();
4✔
5373

5374
   (void)p_specify_terminal_descriptor();
20✔
5375

5376
   if (optional(tTRPLAMP))
20✔
5377
      p_timing_check_condition();
4✔
5378

5379
   return NULL;
20✔
5380
}
5381

5382
static vlog_node_t p_controlled_timing_check_event(void)
4✔
5383
{
5384
   // timing_check_event_control specify_terminal_descriptor
5385
   //    [ &&& timing_check_condition ]
5386

5387
   BEGIN("controlled timing check event");
8✔
5388

5389
   p_timing_check_event_control();
4✔
5390

5391
   (void)p_specify_terminal_descriptor();
4✔
5392

5393
   if (optional(tTRPLAMP))
4✔
UNCOV
5394
      p_timing_check_condition();
×
5395

5396
   return NULL;
4✔
5397
}
5398

5399
static vlog_node_t p_setup_or_hold_timing_check(void)
6✔
5400
{
5401
   // $setup ( data_event , reference_event , timing_check_limit
5402
   //   [ , [ notifier ] ] ) ;
5403
   //
5404
   // $hold ( reference_event , data_event , timing_check_limit
5405
   //   [ , [ notifier ] ] ) ;
5406

5407
   BEGIN("setup/hold timing check");
12✔
5408

5409
   one_of(tDLRSETUP, tDLRHOLD);
6✔
5410
   consume(tLPAREN);
6✔
5411

5412
   (void)p_timing_check_event();
6✔
5413

5414
   consume(tCOMMA);
6✔
5415

5416
   (void)p_timing_check_event();
6✔
5417

5418
   consume(tCOMMA);
6✔
5419

5420
   (void)p_expression();
6✔
5421

5422
   if (optional(tCOMMA)) {
6✔
5423
      if (peek() == tID)
4✔
5424
         p_identifier();
2✔
5425
   }
5426

5427
   consume(tRPAREN);
6✔
5428
   consume(tSEMI);
6✔
5429

5430
   return NULL;
6✔
5431
}
5432

5433
static vlog_node_t p_recovery_or_removal_timing_check(void)
2✔
5434
{
5435
   // $recovery ( reference_event , data_event , timing_check_limit
5436
   //   [ , [ notifier ] ] ) ;
5437
   //
5438
   // $removal ( reference_event , data_event , timing_check_limit
5439
   //   [ , [ notifier ] ] ) ;
5440

5441
   BEGIN("recovery/removal timing check");
4✔
5442

5443
   one_of(tDLRRECOVERY, tDLRREMOVAL);
2✔
5444
   consume(tLPAREN);
2✔
5445

5446
   (void)p_timing_check_event();
2✔
5447

5448
   consume(tCOMMA);
2✔
5449

5450
   (void)p_timing_check_event();
2✔
5451

5452
   consume(tCOMMA);
2✔
5453

5454
   (void)p_expression();
2✔
5455

5456
   if (optional(tCOMMA)) {
2✔
UNCOV
5457
      if (peek() == tID)
×
UNCOV
5458
         p_identifier();
×
5459
   }
5460

5461
   consume(tRPAREN);
2✔
5462
   consume(tSEMI);
2✔
5463

5464
   return NULL;
2✔
5465
}
5466

5467
static vlog_node_t p_width_timing_check(void)
1✔
5468
{
5469
   // $width ( controlled_reference_event , timing_check_limit , threshold
5470
   //   [ , [ notifier ] ] ) ;
5471

5472
   BEGIN("width timing check");
2✔
5473

5474
   consume(tDLRWIDTH);
1✔
5475
   consume(tLPAREN);
1✔
5476

5477
   (void)p_controlled_timing_check_event();
1✔
5478

5479
   consume(tCOMMA);
1✔
5480

5481
   (void)p_expression();
1✔
5482

5483
   consume(tCOMMA);
1✔
5484

5485
   (void)p_constant_expression();
1✔
5486

5487
   if (optional(tCOMMA)) {
1✔
UNCOV
5488
      if (peek() == tID)
×
UNCOV
5489
         p_identifier();
×
5490
   }
5491

5492
   consume(tRPAREN);
1✔
5493
   consume(tSEMI);
1✔
5494

5495
   return NULL;
1✔
5496
}
5497

5498
static vlog_node_t p_delayed_data_or_reference(void)
2✔
5499
{
5500
   // terminal_identifier
5501
   //   | terminal_identifier [ constant_mintypmax_expression ]
5502

5503
   BEGIN("delayed data/reference");
4✔
5504

5505
   p_identifier();
2✔
5506

5507
   return NULL;
2✔
5508
}
5509

5510
static vlog_node_t p_period_timing_check(void)
3✔
5511
{
5512
   // $period ( controlled_reference_event , timing_check_limit
5513
   //   [ , [ notifier ] ] ) ;
5514

5515
   BEGIN("period timing check");
6✔
5516

5517
   consume(tDLRPERIOD);
3✔
5518
   consume(tLPAREN);
3✔
5519

5520
   (void)p_controlled_timing_check_event();
3✔
5521

5522
   consume(tCOMMA);
3✔
5523

5524
   (void)p_expression();
3✔
5525

5526
   if (optional(tCOMMA)) {
3✔
5527
      if (peek() == tID)
2✔
5528
         p_identifier();
1✔
5529
   }
5530

5531
   consume(tRPAREN);
3✔
5532
   consume(tSEMI);
3✔
5533

5534
   return NULL;
3✔
5535
}
5536

5537
static vlog_node_t p_setuphold_or_recrem_timing_check(void)
2✔
5538
{
5539
   // $setuphold ( reference_event , data_event , timing_check_limit ,
5540
   //    timing_check_limit [ , [ notifier ] [ , [ timestamp_condition ]
5541
   //    [ , [ timecheck_condition ] [ , [ delayed_reference ]
5542
   //    [ , [ delayed_data ] ] ] ] ] ] ) ;
5543

5544
   BEGIN("setuphold/recrem timing check");
4✔
5545

5546
   one_of(tDLRSETUPHOLD, tDLRRECREM);
2✔
5547
   consume(tLPAREN);
2✔
5548

5549
   (void)p_timing_check_event();
2✔
5550

5551
   consume(tCOMMA);
2✔
5552

5553
   (void)p_timing_check_event();
2✔
5554

5555
   consume(tCOMMA);
2✔
5556

5557
   (void)p_expression();
2✔
5558

5559
   consume(tCOMMA);
2✔
5560

5561
   (void)p_expression();
2✔
5562

5563
   if (optional(tCOMMA)) {
2✔
5564
      if (peek() == tID)
2✔
5565
         p_identifier(); // notifier
2✔
5566

5567
      if (optional(tCOMMA)) {
2✔
5568
         if (not_at_token(tCOMMA, tRPAREN))
2✔
5569
            (void)p_mintypmax_expression();  // timestamp_condition
×
5570

5571
         if (optional(tCOMMA)) {
2✔
5572
            if (not_at_token(tCOMMA, tRPAREN))
2✔
UNCOV
5573
               (void)p_mintypmax_expression();  // timecheck_condition
×
5574

5575
            if (optional(tCOMMA)) {
2✔
5576
               if (not_at_token(tCOMMA, tRPAREN))
2✔
5577
                  p_delayed_data_or_reference();  // delayed_reference
1✔
5578

5579
               if (optional(tCOMMA)) {
2✔
5580
                  if (not_at_token(tCOMMA, tRPAREN))
2✔
5581
                     p_delayed_data_or_reference();  // delayed_data
1✔
5582
               }
5583
            }
5584
         }
5585
      }
5586
   }
5587

5588
   consume(tRPAREN);
2✔
5589
   consume(tSEMI);
2✔
5590

5591
   return NULL;
2✔
5592
}
5593

5594
static vlog_node_t p_system_timing_check(void)
14✔
5595
{
5596
   // $setup_timing_check | $hold_timing_check | $setuphold_timing_check
5597
   //   | $recovery_timing_check | $removal_timing_check | $recrem_timing_check
5598
   //   | $skew_timing_check | $timeskew_timing_check | $fullskew_timing_check
5599
   //   | $period_timing_check | $width_timing_check | $nochange_timing_check
5600

5601
   BEGIN("system timing check");
28✔
5602

5603
   switch (peek()) {
14✔
5604
   case tDLRSETUP:
6✔
5605
   case tDLRHOLD:
5606
      return p_setup_or_hold_timing_check();
6✔
5607
   case tDLRRECOVERY:
2✔
5608
   case tDLRREMOVAL:
5609
      return p_recovery_or_removal_timing_check();
2✔
5610
   case tDLRWIDTH:
1✔
5611
      return p_width_timing_check();
1✔
5612
   case tDLRPERIOD:
3✔
5613
      return p_period_timing_check();
3✔
5614
   case tDLRSETUPHOLD:
2✔
5615
   case tDLRRECREM:
5616
      return p_setuphold_or_recrem_timing_check();
2✔
UNCOV
5617
   default:
×
5618
      should_not_reach_here();
5619
   }
5620
}
5621

5622
static vlog_node_t p_pulse_control_specparam(void)
1✔
5623
{
5624
   // PATHPULSE$ = (reject_limit_value [, error_limit_value])
5625
   //   | PATHPULSE$specify_input_terminal_descriptor
5626
   //       $specify_output_terminal_descriptor =
5627
   //       (reject_limit_value [, error_limit_value])
5628

5629
   BEGIN("pulse control specparam");
2✔
5630

5631
   vlog_node_t v = vlog_new(V_SPECPARAM);
1✔
5632

5633
   consume(tPATHPULSE);
1✔
5634

5635
   consume(tEQ);
1✔
5636
   consume(tLPAREN);
1✔
5637

5638
   vlog_set_value(v, p_constant_mintypmax_expression());
1✔
5639

5640
   if (optional(tCOMMA))
1✔
5641
      (void)p_constant_mintypmax_expression();
1✔
5642

5643
   consume(tRPAREN);
1✔
5644

5645
   vlog_set_loc(v, CURRENT_LOC);
1✔
5646
   return v;
1✔
5647
}
5648

5649
static vlog_node_t p_specparam_assignment(void)
4✔
5650
{
5651
   // specparam_identifier = constant_mintypmax_expression
5652
   //   | pulse_control_specparam
5653

5654
   BEGIN("specparam assignment");
8✔
5655

5656
   if (peek() == tPATHPULSE)
4✔
5657
      return p_pulse_control_specparam();
1✔
5658
   else {
5659
      vlog_node_t v = vlog_new(V_SPECPARAM);
3✔
5660
      vlog_set_ident(v, p_identifier());
3✔
5661

5662
      consume(tEQ);
3✔
5663

5664
      vlog_set_value(v, p_constant_mintypmax_expression());
3✔
5665

5666
      vlog_set_loc(v, CURRENT_LOC);
3✔
5667
      vlog_symtab_put(symtab, v);
3✔
5668
      return v;
3✔
5669
   }
5670
}
5671

5672
static void p_list_of_specparam_assignments(vlog_node_t parent)
4✔
5673
{
5674
   // specparam_assignment { , specparam_assignment }
5675

5676
   BEGIN("list of specparam assignments");
8✔
5677

5678
   do {
4✔
5679
      vlog_add_decl(parent, p_specparam_assignment());
4✔
5680
   } while (optional(tCOMMA));
4✔
5681
}
4✔
5682

5683
static void p_specparam_declaration(vlog_node_t parent)
4✔
5684
{
5685
   // specparam [ packed_dimension ] list_of_specparam_assignments ;
5686

5687
   BEGIN("specparam declaration");
8✔
5688

5689
   consume(tSPECPARAM);
4✔
5690

5691
   if (peek() == tLSQUARE)
4✔
5692
      (void)p_packed_dimension();
1✔
5693

5694
   p_list_of_specparam_assignments(parent);
4✔
5695

5696
   consume(tSEMI);
4✔
5697
}
4✔
5698

5699
static void p_specify_item(vlog_node_t parent)
36✔
5700
{
5701
   // specparam_declaration | pulsestyle_declaration | showcancelled_declaration
5702
   //   | path_declaration | system_timing_check
5703

5704
   BEGIN("specify item");
72✔
5705

5706
   switch (peek()) {
36✔
5707
   case tSPECPARAM:
4✔
5708
      p_specparam_declaration(parent);
4✔
5709
      break;
4✔
5710
   case tLPAREN:
18✔
5711
   case tIF:
5712
   case tIFNONE:
5713
      (void)p_path_declaration();
18✔
5714
      break;
18✔
5715
   case tDLRSETUP:
14✔
5716
   case tDLRHOLD:
5717
   case tDLRRECOVERY:
5718
   case tDLRREMOVAL:
5719
   case tDLRSETUPHOLD:
5720
   case tDLRRECREM:
5721
   case tDLRWIDTH:
5722
   case tDLRPERIOD:
5723
      (void)p_system_timing_check();
14✔
5724
      break;
14✔
UNCOV
5725
   default:
×
UNCOV
5726
      one_of(tSPECPARAM, tLPAREN, tIF, tIFNONE, tDLRSETUP, tDLRHOLD,
×
5727
             tDLRRECOVERY, tDLRREMOVAL, tDLRSETUPHOLD, tDLRRECREM,
5728
             tDLRWIDTH, tDLRPERIOD);
5729
   }
5730
}
36✔
5731

5732
static vlog_node_t p_specify_block(void)
3✔
5733
{
5734
   // specify { specify_item } endspecify
5735

5736
   BEGIN("specify block");
6✔
5737

5738
   consume(tSPECIFY);
3✔
5739

5740
   vlog_node_t v = vlog_new(V_SPECIFY);
3✔
5741
   vlog_set_loc(v, CURRENT_LOC);
3✔
5742

5743
   vlog_symtab_push(symtab, v);
3✔
5744

5745
   while (not_at_token(tENDSPECIFY))
39✔
5746
      p_specify_item(v);
36✔
5747

5748
   vlog_symtab_pop(symtab);
3✔
5749

5750
   consume(tENDSPECIFY);
3✔
5751

5752
   vlog_set_loc(v, CURRENT_LOC);
3✔
5753
   return v;
3✔
5754
}
5755

5756
static vlog_node_t p_ordered_port_connection(void)
215✔
5757
{
5758
   // { attribute_instance } [ expression ]
5759

5760
   BEGIN("ordered port connection");
430✔
5761

5762
   optional_attributes();
215✔
5763

5764
   vlog_node_t v = vlog_new(V_PORT_CONN);
215✔
5765

5766
   if (not_at_token(tCOMMA, tRPAREN))
215✔
5767
      vlog_set_value(v, p_expression());
215✔
5768

5769
   vlog_set_loc(v, CURRENT_LOC);
215✔
5770
   return v;
215✔
5771
}
5772

5773
static vlog_node_t p_named_port_connection(void)
135✔
5774
{
5775
   // { attribute_instance } . port_identifier [ ( [ expression ] ) ]
5776
   //    | { attribute_instance } .*
5777

5778
   BEGIN("named port connection");
270✔
5779

5780
   optional_attributes();
135✔
5781

5782
   vlog_node_t v = vlog_new(V_PORT_CONN);
135✔
5783

5784
   consume(tDOT);
135✔
5785

5786
   vlog_set_ident(v, p_identifier());
135✔
5787

5788
   if (optional(tLPAREN)) {
135✔
5789

5790
      if (peek() != tRPAREN)
135✔
5791
         vlog_set_value(v, p_expression());
133✔
5792

5793
      consume(tRPAREN);
135✔
5794
   }
5795

5796
   vlog_set_loc(v, CURRENT_LOC);
135✔
5797
   return v;
135✔
5798
}
5799

5800
static void p_list_of_port_connections(vlog_node_t inst)
152✔
5801
{
5802
   // ordered_port_connection { , ordered_port_connection }
5803
   //   | named_port_connection { , named_port_connection }
5804

5805
   BEGIN("list of port connections");
304✔
5806

5807
   vlog_symtab_set_implicit(symtab, implicit_kind);
152✔
5808

5809
   do {
350✔
5810
      skip_over_attributes();
350✔
5811

5812
      if (peek() == tDOT)
350✔
5813
         vlog_add_param(inst, p_named_port_connection());
135✔
5814
      else
5815
         vlog_add_param(inst, p_ordered_port_connection());
215✔
5816
   } while (optional(tCOMMA));
350✔
5817

5818
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
152✔
5819
}
152✔
5820

5821
static vlog_node_t p_hierarchical_instance(void)
148✔
5822
{
5823
   // name_of_instance ( [ list_of_port_connections ] )
5824

5825
   BEGIN("hierarchical instance");
296✔
5826

5827
   vlog_node_t v = vlog_new(V_MOD_INST);
148✔
5828
   vlog_set_ident(v, p_identifier());
148✔
5829

5830
   consume(tLPAREN);
148✔
5831

5832
   if (peek() != tRPAREN)
148✔
5833
      p_list_of_port_connections(v);
135✔
5834

5835
   consume(tRPAREN);
148✔
5836

5837
   vlog_set_loc(v, CURRENT_LOC);
148✔
5838
   vlog_symtab_put(symtab, v);
148✔
5839
   return v;
148✔
5840
}
5841

5842
static vlog_node_t p_udp_instance(void)
17✔
5843
{
5844
   // [ name_of_instance ] ( output_terminal , input_terminal
5845
   //   { , input_terminal } )
5846

5847
   BEGIN("udp instance");
34✔
5848

5849
   vlog_node_t v = vlog_new(V_MOD_INST);
17✔
5850
   if (peek() == tID)
17✔
UNCOV
5851
      vlog_set_ident(v, p_identifier());
×
5852
   else
5853
      vlog_set_ident(v, ident_uniq("$unnamed"));
17✔
5854

5855
   consume(tLPAREN);
17✔
5856

5857
   p_list_of_port_connections(v);
17✔
5858

5859
   consume(tRPAREN);
17✔
5860

5861
   vlog_set_loc(v, CURRENT_LOC);
17✔
5862
   return v;
17✔
5863
}
5864

5865
static vlog_node_t p_param_expression(void)
66✔
5866
{
5867
   // mintypmax_expression | data_type | $
5868

5869
   BEGIN("param expression");
132✔
5870

5871
   return p_expression();   // TODO
66✔
5872
}
5873

5874
static vlog_node_t p_named_parameter_assignment(void)
18✔
5875
{
5876
   // . parameter_identifier ( [ param_expression ] )
5877

5878
   BEGIN("named parameter assignment");
36✔
5879

5880
   consume(tDOT);
18✔
5881

5882
   vlog_node_t v = vlog_new(V_PARAM_ASSIGN);
18✔
5883
   vlog_set_ident(v, p_identifier());
18✔
5884

5885
   consume(tLPAREN);
18✔
5886

5887
   if (peek() != tRPAREN)
18✔
5888
      vlog_set_value(v, p_param_expression());
14✔
5889

5890
   consume(tRPAREN);
18✔
5891

5892
   vlog_set_loc(v, CURRENT_LOC);
18✔
5893
   return v;
18✔
5894
}
5895

5896
static vlog_node_t p_ordered_parameter_assignment(void)
52✔
5897
{
5898
   // param_expression
5899

5900
   BEGIN("ordered parameter assignment");
104✔
5901

5902
   vlog_node_t v = vlog_new(V_PARAM_ASSIGN);
52✔
5903
   vlog_set_value(v, p_param_expression());
52✔
5904

5905
   vlog_set_loc(v, CURRENT_LOC);
52✔
5906
   return v;
52✔
5907
}
5908

5909
static void p_list_of_parameter_assignments(vlog_node_t inst)
60✔
5910
{
5911
   // ordered_parameter_assignment { , ordered_parameter_assignment }
5912
   //   | named_parameter_assignment { , named_parameter_assignment }
5913

5914
   BEGIN("list of parameter assignments");
120✔
5915

5916
   do {
70✔
5917
      if (peek() == tDOT)
70✔
5918
         vlog_add_param(inst, p_named_parameter_assignment());
18✔
5919
      else
5920
         vlog_add_param(inst, p_ordered_parameter_assignment());
52✔
5921
   } while (optional(tCOMMA));
70✔
5922
}
60✔
5923

5924
static void p_parameter_value_assignment(vlog_node_t inst)
60✔
5925
{
5926
   // # ( [ list_of_parameter_assignments ] )
5927

5928
   BEGIN("parameter value assignment");
120✔
5929

5930
   consume(tHASH);
60✔
5931
   consume(tLPAREN);
60✔
5932

5933
   if (peek() != tRPAREN)
60✔
5934
      p_list_of_parameter_assignments(inst);
60✔
5935

5936
   consume(tRPAREN);
60✔
5937
}
60✔
5938

5939
static void p_module_or_udp_instantiation(vlog_node_t mod)
159✔
5940
{
5941
   // module_identifier [ parameter_value_assignment ] hierarchical_instance
5942
   //   { , hierarchical_instance } ;
5943
   //
5944
   // udp_identifier [ drive_strength ] [ delay2 ] udp_instance
5945
   //   { , udp_instance } ;
5946

5947
   BEGIN("module instantiation");
318✔
5948

5949
   vlog_node_t v = vlog_new(V_INST_LIST);
159✔
5950
   vlog_set_ident(v, p_identifier());
159✔
5951

5952
   if (peek() == tHASH)
159✔
5953
      p_parameter_value_assignment(v);
60✔
5954

5955
   do {
165✔
5956
      if (peek() == tLPAREN)
165✔
5957
         vlog_add_stmt(v, p_udp_instance());
17✔
5958
      else
5959
         vlog_add_stmt(v, p_hierarchical_instance());
148✔
5960
   } while (optional(tCOMMA));
165✔
5961

5962
   consume(tSEMI);
159✔
5963

5964
   vlog_set_loc(v, CURRENT_LOC);
159✔
5965

5966
   vlog_add_stmt(mod, v);
159✔
5967
}
159✔
5968

5969
static vlog_node_t p_defparam_assignment(void)
3✔
5970
{
5971
   // hierarchical_parameter_identifier = constant_mintypmax_expression
5972

5973
   BEGIN("defparam assignment");
6✔
5974

5975
   vlog_node_t v = vlog_new(V_DEFPARAM);
3✔
5976
   vlog_set_target(v, p_hierarchical_identifier(NULL));
3✔
5977

5978
   consume(tEQ);
3✔
5979

5980
   vlog_set_value(v, p_constant_mintypmax_expression());
3✔
5981

5982
   vlog_set_loc(v, CURRENT_LOC);
3✔
5983
   return v;
3✔
5984
}
5985

5986
static void p_list_of_defparam_assignments(vlog_node_t parent)
3✔
5987
{
5988
   // defparam_assignment { , defparam_assignment }
5989

5990
   BEGIN("list of defparam assignments");
6✔
5991

5992
   do {
3✔
5993
      vlog_add_stmt(parent, p_defparam_assignment());
3✔
5994
   } while (optional(tCOMMA));
3✔
5995
}
3✔
5996

5997
static void p_parameter_override(vlog_node_t parent)
3✔
5998
{
5999
   // defparam list_of_defparam_assignments ;
6000

6001
   BEGIN("parameter override");
6✔
6002

6003
   consume(tDEFPARAM);
3✔
6004

6005
   p_list_of_defparam_assignments(parent);
3✔
6006

6007
   consume(tSEMI);
3✔
6008
}
3✔
6009

6010
static void p_module_or_generate_item(vlog_node_t mod)
5,975✔
6011
{
6012
   // { attribute_instance } parameter_override
6013
   //   | { attribute_instance } gate_instantiation
6014
   //   | { attribute_instance } udp_instantiation
6015
   //   | { attribute_instance } module_instantiation
6016
   //   | { attribute_instance } module_common_item
6017

6018
   BEGIN("module or generate item");
11,950✔
6019

6020
   optional_attributes();
5,975✔
6021

6022
   switch (peek()) {
5,975✔
6023
   case tALWAYS:
5,742✔
6024
   case tALWAYSCOMB:
6025
   case tALWAYSFF:
6026
   case tALWAYSLATCH:
6027
   case tWIRE:
6028
   case tUWIRE:
6029
   case tSUPPLY0:
6030
   case tSUPPLY1:
6031
   case tTRI:
6032
   case tTRI0:
6033
   case tTRI1:
6034
   case tTRIAND:
6035
   case tTRIOR:
6036
   case tTRIREG:
6037
   case tWAND:
6038
   case tWOR:
6039
   case tINTERCONNECT:
6040
   case tREG:
6041
   case tSTRUCT:
6042
   case tUNION:
6043
   case tASSIGN:
6044
   case tINITIAL:
6045
   case tTYPEDEF:
6046
   case tENUM:
6047
   case tSVINT:
6048
   case tINTEGER:
6049
   case tSVREAL:
6050
   case tSHORTREAL:
6051
   case tREALTIME:
6052
   case tTIME:
6053
   case tTASK:
6054
   case tFUNCTION:
6055
   case tLOCALPARAM:
6056
   case tPARAMETER:
6057
   case tIF:
6058
   case tCASE:
6059
   case tFOR:
6060
   case tEVENT:
6061
   case tGENVAR:
6062
   case tVAR:
6063
   case tLOGIC:
6064
   case tBIT:
6065
   case tSHORTINT:
6066
   case tLONGINT:
6067
   case tBYTE:
6068
   case tSTRINGK:
6069
   case tIMPORT:
6070
      p_module_common_item(mod);
5,742✔
6071
      break;
5,742✔
6072
   case tPULLDOWN:
60✔
6073
   case tPULLUP:
6074
   case tAND:
6075
   case tNAND:
6076
   case tOR:
6077
   case tNOR:
6078
   case tXOR:
6079
   case tXNOR:
6080
   case tNOT:
6081
   case tBUF:
6082
   case tBUFIF0:
6083
   case tBUFIF1:
6084
   case tNOTIF0:
6085
   case tNOTIF1:
6086
   case tTRAN:
6087
   case tTRANIF0:
6088
   case tTRANIF1:
6089
   case tRTRAN:
6090
   case tRTRANIF0:
6091
   case tRTRANIF1:
6092
      p_gate_instantiation(mod);
60✔
6093
      break;
60✔
6094
   case tDEFPARAM:
3✔
6095
      p_parameter_override(mod);
3✔
6096
      break;
3✔
6097
   case tID:
170✔
6098
      {
6099
         vlog_node_t ref = peek_reference();
170✔
6100
         if (ref == NULL)
170✔
6101
            p_module_or_udp_instantiation(mod);
159✔
6102
         else
6103
            p_module_common_item(mod);
11✔
6104
      }
6105
      break;
UNCOV
6106
   default:
×
UNCOV
6107
      expect(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
×
6108
             tSUPPLY0, tSUPPLY1, tTRI,  tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
6109
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tASSIGN,
6110
             tINITIAL, tTYPEDEF, tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL,
6111
             tREALTIME, tTIME, tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER, tIF,
6112
             tFOR, tEVENT, tGENVAR, tVAR, tLOGIC, tBIT, tSHORTINT, tLONGINT,
6113
             tBYTE, tSTRINGK, tIMPORT, tPULLDOWN, tPULLUP, tID, tAND, tNAND,
6114
             tOR, tNOR, tXOR, tXNOR, tNOT, tBUF, tBUFIF0, tBUFIF1, tNOTIF0,
6115
             tNOTIF1, tDEFPARAM, tID);
UNCOV
6116
      drop_tokens_until(&state, tSEMI);
×
6117
   }
6118
}
5,975✔
6119

6120
static void p_generate_region(vlog_node_t mod)
20✔
6121
{
6122
   // generate { generate_item } endgenerate
6123

6124
   BEGIN("generate region");
40✔
6125

6126
   // Has no real meaning in System Verilog
6127

6128
   // TODO: generate regions do not nest so check mod is V_MODULE
6129

6130
   consume(tGENERATE);
20✔
6131

6132
   if (optional(tBEGIN)) {
20✔
6133
      // This is non-standard but seen in some legacy code
6134
      consume(tCOLON);
1✔
6135

6136
      vlog_node_t b = vlog_new(V_BLOCK);
1✔
6137
      vlog_set_ident(b, p_identifier());
1✔
6138

6139
      while (not_at_token(tEND))
1✔
UNCOV
6140
         p_generate_item(b);
×
6141

6142
      consume(tEND);
1✔
6143

6144
      vlog_set_loc(b, CURRENT_LOC);
1✔
6145
      vlog_add_stmt(mod, b);
1✔
6146
   }
6147
   else {
6148
      while (not_at_token(tENDGENERATE))
38✔
6149
         p_generate_item(mod);
19✔
6150
   }
6151

6152
   consume(tENDGENERATE);
20✔
6153
}
20✔
6154

6155
static void p_non_port_module_item(vlog_node_t mod)
5,866✔
6156
{
6157
   // generate_region | module_or_generate_item | specify_block
6158
   //   | { attribute_instance } specparam_declaration | program_declaration
6159
   //   | module_declaration | interface_declaration | timeunits_declaration
6160

6161
   BEGIN("non-port module item");
11,732✔
6162

6163
   switch (peek()) {
5,866✔
6164
   case tALWAYS:
5,841✔
6165
   case tALWAYSCOMB:
6166
   case tALWAYSFF:
6167
   case tALWAYSLATCH:
6168
   case tWIRE:
6169
   case tUWIRE:
6170
   case tSUPPLY0:
6171
   case tSUPPLY1:
6172
   case tTRI:
6173
   case tTRI0:
6174
   case tTRI1:
6175
   case tTRIAND:
6176
   case tTRIOR:
6177
   case tTRIREG:
6178
   case tWAND:
6179
   case tWOR:
6180
   case tINTERCONNECT:
6181
   case tREG:
6182
   case tSTRUCT:
6183
   case tUNION:
6184
   case tASSIGN:
6185
   case tINITIAL:
6186
   case tPULLDOWN:
6187
   case tPULLUP:
6188
   case tID:
6189
   case tATTRBEGIN:
6190
   case tAND:
6191
   case tNAND:
6192
   case tOR:
6193
   case tNOR:
6194
   case tXOR:
6195
   case tXNOR:
6196
   case tNOT:
6197
   case tBUF:
6198
   case tBUFIF0:
6199
   case tBUFIF1:
6200
   case tNOTIF0:
6201
   case tNOTIF1:
6202
   case tTRAN:
6203
   case tTRANIF0:
6204
   case tTRANIF1:
6205
   case tRTRAN:
6206
   case tRTRANIF0:
6207
   case tRTRANIF1:
6208
   case tTYPEDEF:
6209
   case tENUM:
6210
   case tSVINT:
6211
   case tINTEGER:
6212
   case tSVREAL:
6213
   case tSHORTREAL:
6214
   case tREALTIME:
6215
   case tTIME:
6216
   case tTASK:
6217
   case tFUNCTION:
6218
   case tLOCALPARAM:
6219
   case tPARAMETER:
6220
   case tEVENT:
6221
   case tIF:
6222
   case tFOR:
6223
   case tGENVAR:
6224
   case tVAR:
6225
   case tLOGIC:
6226
   case tBIT:
6227
   case tSHORTINT:
6228
   case tLONGINT:
6229
   case tBYTE:
6230
   case tSTRINGK:
6231
   case tIMPORT:
6232
   case tDEFPARAM:
6233
      p_module_or_generate_item(mod);
5,841✔
6234
      break;
5,841✔
6235
   case tSPECIFY:
3✔
6236
      vlog_add_stmt(mod, p_specify_block());
3✔
6237
      break;
3✔
6238
   case tGENERATE:
20✔
6239
      p_generate_region(mod);
20✔
6240
      break;
20✔
6241
   default:
2✔
6242
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
2✔
6243
             tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
6244
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tASSIGN,
6245
             tPULLDOWN, tPULLUP, tID, tATTRBEGIN, tAND, tNAND, tOR, tNOR, tXOR,
6246
             tXNOR, tNOT, tBUF, tBUFIF0, tBUFIF1, tNOTIF0, tNOTIF1, tTYPEDEF,
6247
             tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTIME,
6248
             tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER, tEVENT, tIF, tFOR,
6249
             tGENVAR, tVAR, tLOGIC, tBIT, tSHORTINT, tLONGINT, tBYTE, tSTRINGK,
6250
             tIMPORT, tDEFPARAM, tSPECIFY, tGENERATE);
6251
      drop_tokens_until(&state, tSEMI);
2✔
6252
   }
6253
}
5,866✔
6254

6255
static void p_module_item(vlog_node_t mod)
6,297✔
6256
{
6257
   // port_declaration ; | non_port_module_item
6258

6259
   BEGIN("module item");
12,594✔
6260

6261
   skip_over_attributes();
6,297✔
6262

6263
   if (scan(tINOUT, tINPUT, tOUTPUT)) {
6,297✔
6264
      p_port_declaration(mod);
431✔
6265
      consume(tSEMI);
431✔
6266
   }
6267
   else
6268
      p_non_port_module_item(mod);
5,866✔
6269
}
6,297✔
6270

6271
static void p_ansi_port_declaration(vlog_node_t mod, v_port_kind_t *kind,
114✔
6272
                                    vlog_node_t *dt)
6273
{
6274
   // [ net_port_header | interface_port_header ] port_identifier
6275
   //     { unpacked_dimension } [ = constant_expression ]
6276
   // | [ variable_port_header ] port_identifier { variable_dimension }
6277
   //     [ = constant_expression ]
6278
   // | [ port_direction ] . port_identifier ( [ expression ] )
6279

6280
   BEGIN("ANSI port declaration");
228✔
6281

6282
   if (peek() != tID)
114✔
6283
      p_net_port_header(kind, dt);
92✔
6284
   else if (*dt == NULL)
22✔
UNCOV
6285
      *dt = implicit_type();
×
6286

6287
   ident_t id, ext;
114✔
6288
   p_external_identifier(&id, &ext);
114✔
6289

6290
   vlog_node_t v = vlog_new(V_PORT_DECL);
114✔
6291
   vlog_set_subkind(v, *kind);
114✔
6292
   vlog_set_ident(v, id);
114✔
6293
   vlog_set_ident2(v, ext);
114✔
6294
   vlog_set_type(v, *dt);
114✔
6295
   vlog_set_loc(v, &state.last_loc);
114✔
6296

6297
   if (optional(tEQ))
114✔
6298
      vlog_set_value(v, p_constant_expression());
9✔
6299

6300
   vlog_add_decl(mod, v);
114✔
6301
   vlog_symtab_put(symtab, v);
114✔
6302

6303
   vlog_node_t ref = vlog_new(V_REF);
114✔
6304
   vlog_set_loc(ref, CURRENT_LOC);
114✔
6305
   vlog_set_ident(ref, id);
114✔
6306
   vlog_set_ref(ref, v);
114✔
6307

6308
   vlog_add_port(mod, ref);
114✔
6309
}
114✔
6310

6311
static void p_list_of_port_declarations(vlog_node_t mod)
109✔
6312
{
6313
   // ( [ { attribute_instance } ansi_port_declaration
6314
   //   { , { attribute_instance } ansi_port_declaration } ] )
6315

6316
   BEGIN("list of port declarations");
218✔
6317

6318
   consume(tLPAREN);
109✔
6319

6320
   if (peek() != tRPAREN) {
109✔
6321
      v_port_kind_t kind = V_PORT_INPUT;
41✔
6322
      vlog_node_t dt = NULL;
41✔
6323
      do {
114✔
6324
         optional_attributes();
114✔
6325
         p_ansi_port_declaration(mod, &kind, &dt);
114✔
6326
      } while (optional(tCOMMA));
114✔
6327
   }
6328

6329
   consume(tRPAREN);
109✔
6330
}
109✔
6331

6332
static void p_parameter_port_declaration(vlog_node_t mod)
53✔
6333
{
6334
   // parameter_declaration
6335
   //    | local_parameter_declaration
6336
   //    | data_type list_of_param_assignments
6337
   //    | type list_of_type_assignments
6338

6339
   BEGIN("parameter port declaration");
106✔
6340

6341
   switch (peek()) {
53✔
6342
   case tPARAMETER:
47✔
6343
      p_parameter_declaration(mod);
47✔
6344
      break;
47✔
6345
   case tLOCALPARAM:
5✔
6346
      p_local_parameter_declaration(mod);
5✔
6347
      break;
5✔
6348
   default:
1✔
6349
      // TODO: Add parsing of "type" declarations example #(type T = bit)
6350
      {
6351
         vlog_node_t datatype = p_data_type();
1✔
6352
         p_list_of_param_assignments(mod, datatype, V_PARAM_DECL);
1✔
6353
      }
6354
      break;
1✔
6355
   }
6356
}
53✔
6357

6358
static void p_parameter_port_list(vlog_node_t mod)
27✔
6359
{
6360
   // # ( list_of_param_assignments { , parameter_port_declaration } )
6361
   //    | # ( parameter_port_declaration { , parameter_port_declaration } )
6362
   //    | # ( )
6363

6364
   BEGIN("parameter port list");
54✔
6365

6366
   consume(tHASH);
27✔
6367
   consume(tLPAREN);
27✔
6368

6369
   if (peek() != tRPAREN) {
27✔
6370
      do {
54✔
6371
         if (peek() == tID)
54✔
6372
            p_list_of_param_assignments(mod, implicit_type(), V_PARAM_DECL);
1✔
6373
         else
6374
            p_parameter_port_declaration(mod);
53✔
6375
      } while(optional(tCOMMA));
54✔
6376
   }
6377

6378
   consume(tRPAREN);
27✔
6379
}
27✔
6380

6381
static void p_module_ansi_header(vlog_node_t mod)
617✔
6382
{
6383
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
6384
   //    { package_import_declaration } [ parameter_port_list ]
6385
   ///   [ list_of_port_declarations ] ;
6386

6387
   EXTEND("module ANSI header");
1,234✔
6388

6389
   if (peek() == tLPAREN)
617✔
6390
      p_list_of_port_declarations(mod);
109✔
6391

6392
   consume(tSEMI);
617✔
6393

6394
   vlog_set_loc(mod, CURRENT_LOC);
617✔
6395
}
617✔
6396

6397
static vlog_node_t p_port_reference(void)
457✔
6398
{
6399
   // port_identifier constant_select
6400

6401
   BEGIN("port reference");
914✔
6402

6403
   vlog_node_t v = vlog_new(V_REF);
457✔
6404
   vlog_set_ident(v, p_identifier());
457✔
6405
   vlog_set_loc(v, CURRENT_LOC);
457✔
6406
   return v;
457✔
6407
}
6408

6409
static vlog_node_t p_port_expression(void)
457✔
6410
{
6411
   // port_reference | { port_reference { , port_reference } }
6412

6413
   BEGIN("port expression");
914✔
6414

6415
   return p_port_reference();
457✔
6416
}
6417

6418
static vlog_node_t p_port(void)
457✔
6419
{
6420
   // [ port_expression ] | . port_identifier ( [ port_expression ] )
6421

6422
   BEGIN("port");
914✔
6423

6424
   return p_port_expression();
457✔
6425
}
6426

6427
static void p_list_of_ports(vlog_node_t mod)
151✔
6428
{
6429
   // ( port { , port } )
6430

6431
   BEGIN("list of ports");
302✔
6432

6433
   consume(tLPAREN);
151✔
6434

6435
   do {
457✔
6436
      vlog_add_port(mod, p_port());
457✔
6437
   } while (optional(tCOMMA));
457✔
6438

6439
   consume(tRPAREN);
151✔
6440
}
151✔
6441

6442
static void p_module_nonansi_header(vlog_node_t mod)
151✔
6443
{
6444
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
6445
   //    { package_import_declaration } [ parameter_port_list ] list_of_ports ;
6446

6447
   EXTEND("module non-ANSI header");
302✔
6448

6449
   p_list_of_ports(mod);
151✔
6450

6451
   consume(tSEMI);
151✔
6452

6453
   vlog_set_loc(mod, CURRENT_LOC);
151✔
6454
}
151✔
6455

6456
static vlog_node_t p_module_declaration(void)
768✔
6457
{
6458
   // module_nonansi_header [ timeunits_declaration ] { module_item }
6459
   //      endmodule [ : module_identifier ]
6460
   //   | module_ansi_header [ timeunits_declaration ] { non_port_module_item }
6461
   //      endmodule [ : module_identifier ]
6462
   //   | { attribute_instance } module_keyword [ lifetime ] module_identifier
6463
   //      ( .* ) ; [ timeunits_declaration ] { module_item } endmodule
6464
   //      [ : module_identifier ]
6465
   //   | extern module_nonansi_header
6466
   //   | extern module_ansi_header
6467

6468
   BEGIN("module declaration");
1,536✔
6469

6470
   vlog_node_t mod = vlog_new(V_MODULE);
768✔
6471

6472
   optional_attributes();
768✔
6473

6474
   consume(tMODULE);
768✔
6475

6476
   ident_t id, ext;
768✔
6477
   p_external_identifier(&id, &ext);
768✔
6478
   vlog_set_ident2(mod, id);
768✔
6479

6480
   vlog_set_loc(mod, &state.last_loc);
768✔
6481

6482
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
768✔
6483
   vlog_set_ident(mod, qual);
768✔
6484

6485
   vlog_symtab_push(symtab, mod);
768✔
6486

6487
   while (peek() == tIMPORT)
768✔
UNCOV
6488
      p_package_import_declaration(mod);
×
6489

6490
   if (peek() == tHASH) {
768✔
6491
      p_parameter_port_list(mod);
27✔
6492
      param_kind = V_LOCALPARAM;
27✔
6493
   }
6494

6495
   if (peek() == tLPAREN && peek_nth(2) == tID)
768✔
6496
      p_module_nonansi_header(mod);
151✔
6497
   else
6498
      p_module_ansi_header(mod);
617✔
6499

6500
   while (not_at_token(tENDMODULE))
7,065✔
6501
      p_module_item(mod);
6,297✔
6502

6503
   consume(tENDMODULE);
768✔
6504

6505
   if (optional(tCOLON)) {
768✔
6506
      ident_t name = p_identifier();
2✔
6507
      if (id != name)
2✔
6508
         error_at(&state.last_loc, "'%s' does not match module name '%s'",
1✔
6509
                  istr(name), istr(id));
6510
   }
6511

6512
   vlog_symtab_pop(symtab);
768✔
6513
   return mod;
768✔
6514
}
6515

6516
static void p_udp_port_list(vlog_node_t udp)
26✔
6517
{
6518
   // output_port_identifier , input_port_identifier { , input_port_identifier }
6519

6520
   BEGIN("UDP port list");
52✔
6521

6522
   vlog_node_t oref = vlog_new(V_REF);
26✔
6523
   vlog_set_ident(oref, p_identifier());
26✔
6524
   vlog_set_loc(oref, &state.last_loc);
26✔
6525

6526
   vlog_add_port(udp, oref);
26✔
6527

6528
   consume(tCOMMA);
26✔
6529

6530
   vlog_node_t iref = vlog_new(V_REF);
26✔
6531
   vlog_set_ident(iref, p_identifier());
26✔
6532
   vlog_set_loc(iref, &state.last_loc);
26✔
6533

6534
   vlog_add_port(udp, iref);
26✔
6535

6536
   while (optional(tCOMMA)) {
54✔
6537
      vlog_node_t iref = vlog_new(V_REF);
28✔
6538
      vlog_set_ident(iref, p_identifier());
28✔
6539
      vlog_set_loc(iref, &state.last_loc);
28✔
6540

6541
      vlog_add_port(udp, iref);
28✔
6542
   }
6543
}
26✔
6544

6545
static vlog_node_t p_udp_nonansi_declaration(void)
26✔
6546
{
6547
   // { attribute_instance } primitive udp_identifier ( udp_port_list ) ;
6548

6549
   BEGIN("UDP non-ANSI declaration");
52✔
6550

6551
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
26✔
6552

6553
   consume(tPRIMITIVE);
26✔
6554

6555
   ident_t id, ext;
26✔
6556
   p_external_identifier(&id, &ext);
26✔
6557
   vlog_set_ident2(udp, id);
26✔
6558

6559
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
26✔
6560
   vlog_set_ident(udp, qual);
26✔
6561

6562
   consume(tLPAREN);
26✔
6563

6564
   p_udp_port_list(udp);
26✔
6565

6566
   consume(tRPAREN);
26✔
6567
   consume(tSEMI);
26✔
6568

6569
   vlog_set_loc(udp, CURRENT_LOC);
26✔
6570
   return udp;
26✔
6571
}
6572

6573
static void p_list_of_udp_port_identifiers(vlog_node_t udp, v_port_kind_t kind)
27✔
6574
{
6575
   // port_identifier { , port_identifier }
6576

6577
   BEGIN("list of UDP port identifiers");
54✔
6578

6579
   do {
54✔
6580
      ident_t id, ext;
54✔
6581
      p_external_identifier(&id, &ext);
54✔
6582

6583
      vlog_node_t p = vlog_new(V_PORT_DECL);
54✔
6584
      vlog_set_subkind(p, kind);
54✔
6585
      vlog_set_ident(p, id);
54✔
6586
      vlog_set_ident2(p, ext);
54✔
6587
      vlog_set_type(p, implicit_type());
54✔
6588
      vlog_set_loc(p, &state.last_loc);
54✔
6589

6590
      vlog_add_decl(udp, p);
54✔
6591
      vlog_symtab_put(symtab, p);
54✔
6592
   } while (optional(tCOMMA));
54✔
6593
}
27✔
6594

6595
static void p_udp_output_declaration(vlog_node_t udp, bool *has_reg)
27✔
6596
{
6597
   // { attribute_instance } output port_identifier
6598
   //    | { attribute_instance } output reg port_identifier
6599
   //         [ = constant_expression ]
6600

6601
   BEGIN("UDP output declaration");
54✔
6602

6603
   consume(tOUTPUT);
27✔
6604

6605
   const bool isreg = optional(tREG);
27✔
6606

6607
   ident_t id, ext;
27✔
6608
   p_external_identifier(&id, &ext);
27✔
6609

6610
   vlog_node_t v = vlog_new(V_PORT_DECL);
27✔
6611
   vlog_set_subkind(v, V_PORT_OUTPUT);
27✔
6612
   vlog_set_ident(v, id);
27✔
6613
   vlog_set_ident2(v, ext);
27✔
6614
   vlog_set_loc(v, &state.last_loc);
27✔
6615

6616
   if (isreg) {
27✔
6617
      vlog_set_type(v, logic_type());
2✔
6618
      *has_reg = true;
2✔
6619
   }
6620
   else
6621
      vlog_set_type(v, implicit_type());
25✔
6622

6623
   vlog_add_decl(udp, v);
27✔
6624
   vlog_symtab_put(symtab, v);
27✔
6625
}
27✔
6626

6627
static void p_udp_input_declaration(vlog_node_t udp)
27✔
6628
{
6629
   // { attribute_instance } input list_of_udp_port_identifiers
6630

6631
   BEGIN("UDP input declaration");
54✔
6632

6633
   consume(tINPUT);
27✔
6634

6635
   p_list_of_udp_port_identifiers(udp, V_PORT_INPUT);
27✔
6636
}
27✔
6637

6638
static vlog_node_t p_udp_reg_declaration(void)
13✔
6639
{
6640
   // { attribute_instance } reg variable_identifier
6641

6642
   BEGIN("UDP reg declaration");
26✔
6643

6644
   consume(tREG);
13✔
6645

6646
   ident_t id = p_identifier();
13✔
6647

6648
   vlog_node_t reg = vlog_new(V_VAR_DECL);
13✔
6649
   vlog_set_loc(reg, &state.last_loc);
13✔
6650
   vlog_set_ident(reg, id);
13✔
6651
   vlog_set_type(reg, logic_type());
13✔
6652

6653
   return reg;
13✔
6654
}
6655

6656
static void p_udp_port_declaration(vlog_node_t udp, bool *has_reg)
65✔
6657
{
6658
   // udp_output_declaration ; | udp_input_declaration ; | udp_reg_declaration ;
6659

6660
   BEGIN("UDP port declaration");
130✔
6661

6662
   switch (peek()) {
65✔
6663
   case tOUTPUT:
26✔
6664
      p_udp_output_declaration(udp, has_reg);
26✔
6665
      break;
26✔
6666
   case tINPUT:
26✔
6667
      p_udp_input_declaration(udp);
26✔
6668
      break;
26✔
6669
   case tREG:
13✔
6670
      {
6671
         vlog_node_t v = p_udp_reg_declaration();
13✔
6672
         vlog_add_decl(udp, v);
13✔
6673
         vlog_symtab_put(symtab, v);
13✔
6674
         *has_reg = true;
13✔
6675
      }
6676
      break;
13✔
UNCOV
6677
   default:
×
UNCOV
6678
      one_of(tOUTPUT, tINPUT, tREG);
×
UNCOV
6679
      break;
×
6680
   }
6681

6682
   consume(tSEMI);
65✔
6683
}
65✔
6684

6685
static void p_udp_declaration_port_list(vlog_node_t udp, bool *has_reg)
1✔
6686
{
6687
   // udp_output_declaration , udp_input_declaration { , udp_input_declaration }
6688

6689
   BEGIN("UDP declaration port list");
2✔
6690

6691
   p_udp_output_declaration(udp, has_reg);
1✔
6692

6693
   consume(tCOMMA);
1✔
6694

6695
   do {
1✔
6696
      p_udp_input_declaration(udp);
1✔
6697
   } while (optional(tCOMMA));
1✔
6698

6699
   const int ndecls = vlog_decls(udp);
1✔
6700
   for (int i = 0; i < ndecls; i++) {
3✔
6701
      vlog_node_t p = vlog_decl(udp, i);
2✔
6702
      if (vlog_kind(p) != V_PORT_DECL)
2✔
UNCOV
6703
         continue;
×
6704

6705
      vlog_node_t ref = vlog_new(V_REF);
2✔
6706
      vlog_set_loc(ref, vlog_loc(p));
2✔
6707
      vlog_set_ident(ref, vlog_ident(p));
2✔
6708
      vlog_set_ref(ref, p);
2✔
6709

6710
      vlog_add_port(udp, ref);
2✔
6711
   }
6712
}
1✔
6713

6714
static vlog_node_t p_output_symbol(void)
105✔
6715
{
6716
   // 0 | 1 | x | X
6717

6718
   BEGIN("output symbol");
210✔
6719

6720
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
105✔
6721
   vlog_set_subkind(v, V_UDP_SYMBOL_OUTPUT);
105✔
6722

6723
   if (consume(tUDPLEVEL)) {
105✔
6724
      switch (state.last_lval.i64) {
105✔
6725
      case '0':
105✔
6726
      case '1':
6727
      case 'x':
6728
      case 'X':
6729
         vlog_set_ival(v, state.last_lval.i64);
105✔
6730
         break;
105✔
UNCOV
6731
      default:
×
UNCOV
6732
         parse_error(&state.last_loc, "'%c' is not a valid output symbol",
×
6733
                     (char)state.last_lval.i64);
6734
         break;
6735
      }
6736
   }
6737

6738
   vlog_set_loc(v, CURRENT_LOC);
105✔
6739
   return v;
105✔
6740
}
6741

6742
static vlog_node_t p_level_symbol(void)
437✔
6743
{
6744
   // 0 | 1 | x | X | ? | b | B
6745

6746
   BEGIN("level symbol");
874✔
6747

6748
   consume(tUDPLEVEL);
437✔
6749

6750
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
437✔
6751
   vlog_set_subkind(v, V_UDP_SYMBOL_INPUT);
437✔
6752
   vlog_set_ival(v, state.last_lval.i64);
437✔
6753

6754
   vlog_set_loc(v, CURRENT_LOC);
437✔
6755
   return v;
437✔
6756
}
6757

6758
static vlog_node_t p_next_state(void)
101✔
6759
{
6760
   // output_symbol | -
6761

6762
   BEGIN("next state");
202✔
6763

6764
   switch (peek()) {
101✔
6765
   case tMINUS:
35✔
6766
      consume(tMINUS);
35✔
6767
      break;
35✔
6768
   case tUDPLEVEL:
66✔
6769
      return p_output_symbol();
66✔
UNCOV
6770
   default:
×
UNCOV
6771
      one_of(tUDPLEVEL, tMINUS);
×
6772
   }
6773

6774
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
35✔
6775
   vlog_set_subkind(v, V_UDP_SYMBOL_OUTPUT);
35✔
6776
   vlog_set_ival(v, '-');
35✔
6777

6778
   vlog_set_loc(v, CURRENT_LOC);
35✔
6779
   return v;
35✔
6780
}
6781

6782
static vlog_node_t p_edge_symbol(void)
28✔
6783
{
6784
   // r | R | f | F | p | P | n | N | *
6785

6786
   BEGIN("edge symbol");
56✔
6787

6788
   consume(tUDPEDGE);
28✔
6789

6790
   char left, right;
28✔
6791
   switch (state.last_lval.i64) {
28✔
6792
   case 'r': case 'R': left = '0'; right = '1'; break;
UNCOV
6793
   case 'f': case 'F': left = '1'; right = '0'; break;
×
6794
   case 'p': case 'P': left = '?'; right = '1'; break;
8✔
6795
   case 'n': case 'N': left = '?'; right = '0'; break;
4✔
6796
   case '*':           left = '?'; right = '?'; break;
13✔
6797
   default: should_not_reach_here();
6798
   }
6799

6800
   vlog_node_t lsym = vlog_new(V_UDP_LEVEL);
28✔
6801
   vlog_set_ival(lsym, left);
28✔
6802

6803
   vlog_node_t rsym = vlog_new(V_UDP_LEVEL);
28✔
6804
   vlog_set_ival(rsym, right);
28✔
6805

6806
   vlog_node_t v = vlog_new(V_UDP_EDGE);
28✔
6807
   vlog_set_subkind(v, V_UDP_SYMBOL_INPUT);
28✔
6808
   vlog_set_left(v, lsym);
28✔
6809
   vlog_set_right(v, rsym);
28✔
6810

6811
   vlog_set_loc(v, CURRENT_LOC);
28✔
6812
   return v;
28✔
6813
}
6814

6815
static void p_level_input_list(vlog_node_t entry)
39✔
6816
{
6817
   // level_symbol { level_symbol }
6818

6819
   BEGIN("level input list");
78✔
6820

6821
   do {
90✔
6822
      vlog_add_param(entry, p_level_symbol());
90✔
6823
   } while (not_at_token(tCOLON));
90✔
6824
}
39✔
6825

6826
static vlog_node_t p_edge_indicator(void)
101✔
6827
{
6828
   // ( level_symbol level_symbol ) | edge_symbol
6829

6830
   BEGIN("edge indicator");
202✔
6831

6832
   switch (peek()) {
101✔
6833
   case tUDPEDGE:
28✔
6834
      return p_edge_symbol();
28✔
6835
   case tLPAREN:
73✔
6836
      {
6837
         consume(tLPAREN);
73✔
6838

6839
         vlog_node_t v = vlog_new(V_UDP_EDGE);
73✔
6840
         vlog_set_left(v, p_level_symbol());
73✔
6841
         vlog_set_right(v, p_level_symbol());
73✔
6842

6843
         consume(tRPAREN);
73✔
6844

6845
         vlog_set_loc(v, CURRENT_LOC);
73✔
6846
         return v;
73✔
6847
      }
UNCOV
6848
      break;
×
UNCOV
6849
   default:
×
6850
      should_not_reach_here();
6851
   }
6852
}
6853

6854
static void p_seq_input_list(vlog_node_t entry)
101✔
6855
{
6856
   // level_input_list | edge_input_list
6857

6858
   BEGIN("sequential input list");
202✔
6859

6860
   bool have_edge = false;
101✔
6861
   do {
201✔
6862
      switch (peek()) {
201✔
6863
      case tUDPEDGE:
101✔
6864
      case tLPAREN:
6865
         vlog_add_param(entry, p_edge_indicator());
101✔
6866
         if (have_edge)
101✔
6867
            parse_error(&state.last_loc, "a sequential input list may have at "
1✔
6868
                        "most one edge indicator");
6869
         have_edge = true;
6870
         break;
6871

6872
      case tUDPLEVEL:
100✔
6873
         vlog_add_param(entry, p_level_symbol());
100✔
6874
         break;
100✔
6875

UNCOV
6876
      default:
×
UNCOV
6877
         one_of(tUDPEDGE, tUDPIND, tUDPLEVEL);
×
UNCOV
6878
         break;
×
6879
      }
6880
   } while (not_at_token(tCOLON));
201✔
6881
}
101✔
6882

6883
static vlog_node_t p_combinational_entry(void)
39✔
6884
{
6885
   // level_input_list : output_symbol ;
6886

6887
   BEGIN("combinational entry");
78✔
6888

6889
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
39✔
6890
   p_level_input_list(v);
39✔
6891

6892
   consume(tCOLON);
39✔
6893

6894
   vlog_add_param(v, p_output_symbol());
39✔
6895

6896
   consume(tSEMI);
39✔
6897

6898
   vlog_set_loc(v, CURRENT_LOC);
39✔
6899
   return v;
39✔
6900
}
6901

6902
static vlog_node_t p_combinational_body(void)
12✔
6903
{
6904
   // table combinational_entry { combinational_entry } endtable
6905

6906
   BEGIN("combinational UDP body");
24✔
6907

6908
   consume(tTABLE);
12✔
6909

6910
   scan_as_udp();
12✔
6911

6912
   vlog_node_t v = vlog_new(V_UDP_TABLE);
12✔
6913
   vlog_set_subkind(v, V_UDP_COMB);
12✔
6914
   vlog_set_ident(v, ident_new("combinational"));
12✔
6915

6916
   do {
39✔
6917
      vlog_add_param(v, p_combinational_entry());
39✔
6918
   } while (not_at_token(tENDTABLE));
39✔
6919

6920
   scan_as_verilog();
12✔
6921

6922
   consume(tENDTABLE);
12✔
6923

6924
   vlog_set_loc(v, CURRENT_LOC);
12✔
6925
   return v;
12✔
6926
}
6927

6928
static vlog_node_t p_sequential_entry(void)
101✔
6929
{
6930
   // seq_input_list : current_state : next_state ;
6931

6932
   BEGIN("sequential entry");
202✔
6933

6934
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
101✔
6935
   p_seq_input_list(v);
101✔
6936

6937
   consume(tCOLON);
101✔
6938

6939
   vlog_add_param(v, p_level_symbol());
101✔
6940

6941
   consume(tCOLON);
101✔
6942

6943
   vlog_add_param(v, p_next_state());
101✔
6944

6945
   consume(tSEMI);
101✔
6946

6947
   vlog_set_loc(v, CURRENT_LOC);
101✔
6948
   return v;
101✔
6949
}
6950

6951
static vlog_node_t p_udp_initial_statement(void)
6✔
6952
{
6953
   // initial output_port_identifier = init_val ;
6954

6955
   BEGIN("UDP initial statement");
12✔
6956

6957
   consume(tINITIAL);
6✔
6958

6959
   vlog_node_t ref = vlog_new(V_REF);
6✔
6960
   vlog_set_ident(ref, p_identifier());
6✔
6961
   vlog_set_loc(ref, &state.last_loc);
6✔
6962

6963
   vlog_symtab_lookup(symtab, ref);
6✔
6964

6965
   consume(tEQ);
6✔
6966

6967
   vlog_node_t v = vlog_new(V_BASSIGN);
6✔
6968
   vlog_set_target(v, ref);
6✔
6969
   vlog_set_value(v, p_integral_number());
6✔
6970

6971
   consume(tSEMI);
6✔
6972

6973
   vlog_set_loc(v, CURRENT_LOC);
6✔
6974
   return v;
6✔
6975
}
6976

6977
static vlog_node_t p_sequential_body(void)
15✔
6978
{
6979
   // [ udp_initial_statement ] table sequential_entry
6980
   //     { sequential_entry } endtable
6981

6982
   BEGIN("sequential UDP body");
30✔
6983

6984
   vlog_node_t v = vlog_new(V_UDP_TABLE);
15✔
6985
   vlog_set_subkind(v, V_UDP_SEQ);
15✔
6986
   vlog_set_ident(v, ident_new("sequential"));
15✔
6987

6988
   if (peek() == tINITIAL)
15✔
6989
      vlog_add_stmt(v, p_udp_initial_statement());
6✔
6990

6991
   consume(tTABLE);
15✔
6992

6993
   scan_as_udp();
15✔
6994

6995
   do {
101✔
6996
      vlog_add_param(v, p_sequential_entry());
101✔
6997
   } while (not_at_token(tENDTABLE));
101✔
6998

6999
   scan_as_verilog();
15✔
7000

7001
   consume(tENDTABLE);
15✔
7002

7003
   vlog_set_loc(v, CURRENT_LOC);
15✔
7004
   return v;
15✔
7005
}
7006

7007
static vlog_node_t p_udp_body(bool has_reg)
27✔
7008
{
7009
   // combinational_body | sequential_body
7010

7011
   BEGIN("UDP body");
54✔
7012

7013
   if (has_reg)
27✔
7014
      return p_sequential_body();
15✔
7015
   else
7016
      return p_combinational_body();
12✔
7017
}
7018

7019
static vlog_node_t p_udp_ansi_declaration(bool *has_reg)
1✔
7020
{
7021
   // { attribute_instance } primitive udp_identifier
7022
   //    ( udp_declaration_port_list ) ;
7023

7024
   BEGIN("UDP ANSI declaration");
2✔
7025

7026
   optional_attributes();
1✔
7027

7028
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
1✔
7029

7030
   consume(tPRIMITIVE);
1✔
7031

7032
   ident_t id, ext;
1✔
7033
   p_external_identifier(&id, &ext);
1✔
7034
   vlog_set_ident2(udp, id);
1✔
7035

7036
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
1✔
7037
   vlog_set_ident(udp, qual);
1✔
7038

7039
   vlog_symtab_push(symtab, udp);
1✔
7040

7041
   consume(tLPAREN);
1✔
7042

7043
   p_udp_declaration_port_list(udp, has_reg);
1✔
7044

7045
   consume(tRPAREN);
1✔
7046
   consume(tSEMI);
1✔
7047

7048
   vlog_set_loc(udp, CURRENT_LOC);
1✔
7049
   return udp;
1✔
7050
}
7051

7052
static vlog_node_t p_udp_declaration(void)
27✔
7053
{
7054
   // udp_nonansi_declaration udp_port_declaration { udp_port_declaration }
7055
   //        udp_body endprimitive [ : udp_identifier ]
7056
   //   | udp_ansi_declaration udp_body endprimitive [ : udp_identifier ]
7057
   //   | extern udp_nonansi_declaration
7058
   //   | extern udp_ansi_declaration
7059
   //   | { attribute_instance } primitive udp_identifier ( .* ) ;
7060
   //        { udp_port_declaration } udp_body endprimitive [ : udp_identifier ]
7061

7062
   BEGIN("UDP declaration");
54✔
7063

7064
   bool has_reg = false;
27✔
7065
   vlog_node_t udp;
27✔
7066
   if (peek_nth(4) == tID) {
27✔
7067
      udp = p_udp_nonansi_declaration();
26✔
7068

7069
      vlog_symtab_push(symtab, udp);
26✔
7070

7071
      do {
65✔
7072
         p_udp_port_declaration(udp, &has_reg);
65✔
7073
      } while (not_at_token(tTABLE, tINITIAL));
65✔
7074

7075
      const int nports = vlog_ports(udp);
26✔
7076
      for (int i = 0; i < nports; i++)
106✔
7077
         vlog_symtab_lookup(symtab, vlog_port(udp, i));
80✔
7078
   }
7079
   else
7080
      udp = p_udp_ansi_declaration(&has_reg);
1✔
7081

7082
   vlog_add_stmt(udp, p_udp_body(has_reg));
27✔
7083

7084
   vlog_symtab_pop(symtab);
27✔
7085

7086
   consume(tENDPRIMITIVE);
27✔
7087

7088
   return udp;
27✔
7089
}
7090

7091
static void p_package_item(vlog_node_t parent)
16✔
7092
{
7093
   // package_or_generate_item_declaration | anonymous_program
7094
   //   | package_export_declaration | timeunits_declaration
7095

7096
   BEGIN("package item");
32✔
7097

7098
   p_package_or_generate_item_declaration(parent);
16✔
7099
}
16✔
7100

7101
static vlog_node_t p_package_declaration(void)
5✔
7102
{
7103
   // { attribute_instance } package [ lifetime ] package_identifier ;
7104
   //    [ timeunits_declaration ] { { attribute_instance } package_item }
7105
   // endpackage [ : package_identifier ]
7106

7107
   BEGIN("package declaration");
10✔
7108

7109
   consume(tPACKAGE);
5✔
7110

7111
   param_kind = V_LOCALPARAM;
5✔
7112

7113
   if (scan(tSTATIC, tAUTOMATIC))
5✔
UNCOV
7114
      p_lifetime();
×
7115

7116
   vlog_node_t v = vlog_new(V_PACKAGE);
5✔
7117

7118
   ident_t id, ext;
5✔
7119
   p_external_identifier(&id, &ext);
5✔
7120
   vlog_set_ident2(v, id);
5✔
7121

7122
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
5✔
7123
   vlog_set_ident(v, qual);
5✔
7124

7125
   consume(tSEMI);
5✔
7126

7127
   vlog_symtab_push(symtab, v);
5✔
7128

7129
   while (not_at_token(tENDPACKAGE)) {
16✔
7130
      optional_attributes();
11✔
7131
      p_package_item(v);
11✔
7132
   }
7133

7134
   vlog_symtab_pop(symtab);
5✔
7135

7136
   consume(tENDPACKAGE);
5✔
7137

7138
   if (optional(tCOLON)) {
5✔
7139
      ident_t name = p_identifier();
2✔
7140
      if (id != name)
2✔
7141
         error_at(&state.last_loc, "'%s' does not match package name '%s'",
1✔
7142
                  istr(name), istr(id));
7143
   }
7144

7145
   vlog_set_loc(v, CURRENT_LOC);
5✔
7146
   return v;
5✔
7147
}
7148

7149
static vlog_node_t p_program_nonansi_header(void)
6✔
7150
{
7151
   // { attribute_instance } program [ lifetime ] program_identifier
7152
   //    { package_import_declaration } [ parameter_port_list ] list_of_ports ;
7153

7154
   BEGIN("program non-ANSI header");
12✔
7155

7156
   optional_attributes();
6✔
7157

7158
   vlog_node_t v = vlog_new(V_PROGRAM);
6✔
7159

7160
   consume(tPROGRAM);
6✔
7161

7162
   ident_t id, ext;
6✔
7163
   p_external_identifier(&id, &ext);
6✔
7164
   vlog_set_ident2(v, id);
6✔
7165

7166
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
6✔
7167
   vlog_set_ident(v, qual);
6✔
7168

7169
   consume(tSEMI);
6✔
7170

7171
   vlog_set_loc(v, CURRENT_LOC);
6✔
7172
   return v;
6✔
7173
}
7174

7175
static void p_non_port_program_item(vlog_node_t parent)
23✔
7176
{
7177
   // { attribute_instance } continuous_assign
7178
   //   | { attribute_instance } module_or_generate_item_declaration
7179
   //   | { attribute_instance } initial_construct
7180
   //   | { attribute_instance } final_construct
7181
   //   | { attribute_instance } concurrent_assertion_item
7182
   //   | timeunits_declaration
7183
   //   | program_generate_item
7184

7185
   BEGIN("non-port program item");
46✔
7186

7187
   optional_attributes();
23✔
7188

7189
   switch (peek()) {
23✔
7190
   case tINITIAL:
6✔
7191
      vlog_add_stmt(parent, p_initial_construct());
6✔
7192
      break;
6✔
7193
   default:
17✔
7194
      p_module_or_generate_item_declaration(parent);
17✔
7195
      break;
17✔
7196
   }
7197
}
23✔
7198

7199
static vlog_node_t p_program_declaration(void)
6✔
7200
{
7201
   // program_nonansi_header [ timeunits_declaration ] { program_item }
7202
   //       endprogram [ : program_identifier ]
7203
   //   | program_ansi_header [ timeunits_declaration ]
7204
   //       { non_port_program_item }
7205
   //   | { attribute_instance } program program_identifier ( .* ) ;
7206
   //       [ timeunits_declaration ] { program_item } endprogram
7207
   //       [ : program_identifier ]
7208
   //   | extern program_nonansi_header
7209
   //   | extern program_ansi_header
7210

7211
   BEGIN("program declaration");
12✔
7212

7213
   vlog_node_t v = p_program_nonansi_header();
6✔
7214

7215
   while (not_at_token(tENDPROGRAM))
29✔
7216
      p_non_port_program_item(v);
23✔
7217

7218
   consume(tENDPROGRAM);
6✔
7219

7220
   if (optional(tCOLON)) {
6✔
7221
      ident_t name = p_identifier();
1✔
7222
      if (name != vlog_ident2(v))
1✔
7223
         parse_error(&state.last_loc, "'%s' does not match program name '%s'",
1✔
7224
                     istr(name), istr(vlog_ident2(v)));
7225
   }
7226

7227
   vlog_set_loc(v, CURRENT_LOC);
6✔
7228
   return v;
6✔
7229
}
7230

7231
static vlog_node_t p_description(void)
811✔
7232
{
7233
   // module_declaration | udp_declaration | interface_declaration
7234
   //   | program_declaration | package_declaration
7235
   //   | { attribute_instance } package_item
7236
   //   | { attribute_instance } bind_directive
7237
   //   | config_declaration
7238

7239
   BEGIN("description");
1,622✔
7240

7241
   skip_over_attributes();
811✔
7242

7243
   switch (peek()) {
811✔
7244
   case tMODULE:
768✔
7245
      return p_module_declaration();
768✔
7246
   case tPRIMITIVE:
27✔
7247
      return p_udp_declaration();
27✔
7248
   case tPACKAGE:
5✔
7249
      return p_package_declaration();
5✔
7250
   case tPROGRAM:
6✔
7251
      return p_program_declaration();
6✔
7252
   case tCLASS:
5✔
7253
   case tTYPEDEF:
7254
   case tIMPORT:
7255
      {
7256
         vlog_node_t v = vlog_new(V_NAMESPACE);
5✔
7257
         p_package_item(v);
5✔
7258
         vlog_set_loc(v, CURRENT_LOC);
5✔
7259
         return v;
5✔
7260
      }
UNCOV
7261
   default:
×
UNCOV
7262
      expect(tPRIMITIVE, tMODULE, tPACKAGE, tPROGRAM, tCLASS, tTYPEDEF,
×
7263
             tIMPORT);
UNCOV
7264
      return NULL;
×
7265
   }
7266
}
7267

7268
static void p_timescale_compiler_directive(void)
21✔
7269
{
7270
   // `timescale time_unit / time_precision
7271

7272
   BEGIN("timescale compiler directive");
42✔
7273

7274
   consume(tTIMESCALE);
21✔
7275

7276
   uint64_t unit_value = 1;
21✔
7277
   if (consume(tUNSNUM))
21✔
7278
      unit_value = atoll(state.last_lval.str);
20✔
7279

7280
   const char *unit_name = "fs";
21✔
7281
   if (consume(tID))
21✔
7282
      unit_name = istr(state.last_lval.ident);
21✔
7283

7284
   consume(tOVER);
21✔
7285

7286
   uint64_t prec_value = 1;
21✔
7287
   if (consume(tUNSNUM))
21✔
7288
      prec_value = atoll(state.last_lval.str);
20✔
7289

7290
   const char *prec_name = "fs";
21✔
7291
   if (consume(tID))
21✔
7292
      prec_name = istr(state.last_lval.ident);
20✔
7293

7294
   set_timescale(unit_value, unit_name, prec_value, prec_name, CURRENT_LOC);
21✔
7295
}
21✔
7296

7297
static void p_defaultnettype_compiler_directive(void)
12✔
7298
{
7299
   // `default_nettype wire | tri | tri0 | tri1 | wand | triand | wor
7300
   //    | trior | trireg | uwire | none
7301

7302
   BEGIN("default_nettype directive");
24✔
7303

7304
   consume(tDEFNETTYPE);
12✔
7305

7306
   switch (one_of(tWIRE, tTRI, tTRI0, tTRI1, tWAND, tTRIAND, tWOR, tTRIOR,
12✔
7307
                  tTRIREG, tUWIRE, tNONE)) {
7308
   case tWIRE: implicit_kind = V_NET_WIRE; break;
1✔
7309
   case tNONE: implicit_kind = V_NET_NONE; break;
1✔
7310
   }
7311
}
12✔
7312

7313
static void p_unconnected_drive_directive(void)
2✔
7314
{
7315
   // `unconnected_drive pull0 | pull1
7316

7317
   BEGIN("unconnected_drive directive");
4✔
7318

7319
   consume(tUNCTDRIVE);
2✔
7320

7321
   // TODO set default drive for unconnected nets
7322
   one_of(tPULL0, tPULL1);
2✔
7323
}
2✔
7324

7325
static void p_nounconnected_drive_directive(void)
1✔
7326
{
7327
   // `nounconnected_drive
7328

7329
   BEGIN("nounconnected_drive directive");
2✔
7330

7331
   consume(tNOUNCTDRIVE);
1✔
7332

7333
   // TODO reset default drive for unconnected nets
7334
}
1✔
7335

7336
static void p_keywords_directive(void)
8✔
7337
{
7338
   // `begin_keywords "version_specifier"
7339

7340
   BEGIN("keywords directive");
16✔
7341

7342
   consume(tBEGINKEYWORDS);
8✔
7343

7344
   if (consume(tSTRING)) {
8✔
7345
      vlog_version_t vers;
7✔
7346
      if (parse_verilog_version(tb_get(state.last_lval.text), &vers))
7✔
7347
         push_keywords(vers);
6✔
7348
      else
7349
         error_at(&state.last_loc, "\"%s\" is not a recognised Verilog or "
1✔
7350
                  "System Verilog version", tb_get(state.last_lval.text));
7351

7352
      tb_free(state.last_lval.text);
7✔
7353
   }
7354
}
8✔
7355

7356
static void p_endkeywords_directive(void)
7✔
7357
{
7358
   // `end_keywords
7359

7360
   BEGIN("endkeywords directive");
14✔
7361

7362
   consume(tENDKEYWORDS);
7✔
7363

7364
   if (!pop_keywords())
7✔
7365
      error_at(&state.last_loc, "`end_keywords directive without matching "
1✔
7366
               "`begin_keywords");
7367
}
7✔
7368

7369
static void p_resetall_directive(void)
1✔
7370
{
7371
   // `resetall
7372

7373
   BEGIN("resetall directive");
2✔
7374

7375
   consume(tRESETALL);
1✔
7376

7377
   implicit_kind = V_NET_WIRE;
1✔
7378
}
1✔
7379

7380
static void p_directive_list(void)
1,459✔
7381
{
7382
   BEGIN("directive list");
2,918✔
7383

7384
   for (;;) {
1,511✔
7385
      switch (peek()) {
1,511✔
7386
      case tDEFNETTYPE:
12✔
7387
         p_defaultnettype_compiler_directive();
12✔
7388
         break;
12✔
7389
      case tTIMESCALE:
21✔
7390
         p_timescale_compiler_directive();
21✔
7391
         break;
21✔
7392
      case tUNCTDRIVE:
2✔
7393
         p_unconnected_drive_directive();
2✔
7394
         break;
2✔
7395
      case tNOUNCTDRIVE:
1✔
7396
         p_nounconnected_drive_directive();
1✔
7397
         break;
1✔
7398
      case tBEGINKEYWORDS:
8✔
7399
         p_keywords_directive();
8✔
7400
         break;
8✔
7401
      case tENDKEYWORDS:
7✔
7402
         p_endkeywords_directive();
7✔
7403
         break;
7✔
7404
      case tRESETALL:
1✔
7405
         p_resetall_directive();
1✔
7406
         break;
1✔
7407
      default:
7408
         return;
1,459✔
7409
      }
7410
   }
7411
}
7412

7413
static vlog_node_t end_of_file(void)
653✔
7414
{
7415
   vlog_symtab_pop(symtab);
653✔
7416
   vlog_symtab_free(symtab);
653✔
7417
   symtab = NULL;
653✔
7418
   return NULL;
653✔
7419
}
7420

7421
static vlog_node_t p_source_text(void)
807✔
7422
{
7423
   // [ timeunits_declaration ] { description }
7424

7425
   BEGIN("source text");
1,614✔
7426

7427
   for (;;) {
812✔
7428
      if (peek() == tEOF) {
812✔
7429
         discard_global_arena();
1✔
7430
         return end_of_file();
1✔
7431
      }
7432

7433
      vlog_node_t v = p_description();
811✔
7434
      if (v == NULL || is_top_level(v))
811✔
7435
         return v;
806✔
7436
   }
7437
}
7438

7439
vlog_node_t vlog_parse(void)
1,459✔
7440
{
7441
   state.n_correct = RECOVER_THRESH;
1,459✔
7442
   param_kind = V_PARAM_DECL;
1,459✔
7443

7444
   for (int i = 0; i < ARRAY_LEN(atom_types); i++)
16,049✔
7445
      atom_types[i] = NULL;
14,590✔
7446

7447
   scan_as_verilog();
1,459✔
7448

7449
   if (symtab == NULL) {
1,459✔
7450
      symtab = vlog_symtab_new();
655✔
7451
      vlog_symtab_push(symtab, NULL);   // Compilation unit scope
655✔
7452
      vlog_symtab_poison(symtab, error_marker());
655✔
7453
   }
7454

7455
   p_directive_list();
1,459✔
7456

7457
   if (peek() == tEOF)
1,459✔
7458
      return end_of_file();
652✔
7459

7460
   make_new_arena();
807✔
7461

7462
   return p_source_text();
807✔
7463
}
7464

7465
void reset_verilog_parser(void)
1,277✔
7466
{
7467
   state.n_correct = RECOVER_THRESH;
1,277✔
7468
   state.tokenq_head = state.tokenq_tail = 0;
1,277✔
7469
   state.lex_fn = processed_yylex;
1,277✔
7470
   state.error_fn = vlog_parse_error_cb;
1,277✔
7471

7472
   implicit_kind = V_NET_WIRE;
1,277✔
7473
   last_attr = NULL;
1,277✔
7474

7475
   if (symtab != NULL) {
1,277✔
UNCOV
7476
      vlog_symtab_free(symtab);
×
UNCOV
7477
      symtab = NULL;
×
7478
   }
7479
}
1,277✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc