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

nickg / nvc / 25935296376

15 May 2026 06:29PM UTC coverage: 92.258% (+0.004%) from 92.254%
25935296376

push

github

nickg
Handle real values with integer formats in vpi_get_value

32 of 43 new or added lines in 2 files covered. (74.42%)

623 existing lines in 14 files now uncovered.

78015 of 84562 relevant lines covered (92.26%)

641925.59 hits per line

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

95.64
/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
static unsigned         next_namespace;
42

43
extern loc_t yylloc;
44

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

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

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

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

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

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

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

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

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

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

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

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

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

132
static void skip_over_attributes(void)
11,288✔
133
{
134
   while (peek() == tATTRBEGIN)
11,308✔
135
      last_attr = p_attribute_instance();
20✔
136
}
11,288✔
137

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

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

154
   last_attr = NULL;
77,744✔
155
}
77,744✔
156

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

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

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

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

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

195
      vlog_node_t right = vlog_new(V_NUMBER);
187✔
196
      vlog_set_number(right, number_from_int(0));
187✔
197

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

203
      atom_types[dt] = r;
187✔
204
   }
205

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

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

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

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

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

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

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

268
static vlog_node_t get_data_type(ident_t id)
57✔
269
{
270
   vlog_node_t v = vlog_symtab_query(symtab, id);
57✔
271
   if (v == NULL) {
57✔
272
      error_at(&state.last_loc, "no data type declaration for '%pi'", id);
1✔
273
      return logic_type();
1✔
274
   }
275
   else if (!is_data_type(v)) {
56✔
276
      diag_t *d = diag_new(DIAG_ERROR, &state.last_loc);
1✔
277
      diag_printf(d, "'%pi' is not a data type", id);
1✔
278
      diag_hint(d, vlog_loc(v), "'%pi' declared here", id);
1✔
279
      diag_emit(d);
1✔
280

281
      return logic_type();
1✔
282
   }
283

284
   return v;
285
}
286

287
static bool scan_block_item_declaration(void)
2,612✔
288
{
289
   return scan(tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM, tSVINT, tINTEGER,
2,612✔
290
               tSVREAL, tSHORTREAL, tREALTIME, tBIT, tLOGIC, tSHORTINT, tTIME);
291
}
292

293
static bool scan_tf_item_declaration(void)
161✔
294
{
295
   return scan(tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM, tSVINT, tINTEGER,
161✔
296
               tSVREAL, tSHORTREAL, tREALTIME, tBIT, tLOGIC, tSHORTINT, tTIME,
297
               tINPUT, tOUTPUT);
298
}
299

300
static ident_t p_identifier(void)
48,263✔
301
{
302
   if (consume(tID))
48,263✔
303
      return state.last_lval.ident;
48,262✔
304
   else
305
      return error_marker();
1✔
306
}
307

308
static void p_external_identifier(ident_t *id, ident_t *ext)
1,638✔
309
{
310
   if (consume(tID)) {
1,638✔
311
      *id = state.last_lval.ident;
1,638✔
312

313
      LOCAL_TEXT_BUF tb = tb_new();
1,638✔
314
      tb_istr(tb, state.last_lval.ident);
1,638✔
315
      tb_upcase(tb);
1,638✔
316

317
      *ext = ident_new(tb_get(tb));
1,638✔
318
   }
319
   else
UNCOV
320
      *id = *ext = error_marker();
×
321
}
1,638✔
322

323
static ident_t p_system_tf_identifier(void)
9,364✔
324
{
325
   if (consume(tSYSTASK))
9,364✔
326
      return state.last_lval.ident;
9,364✔
327
   else
UNCOV
328
      return error_marker();
×
329
}
330

331
static void p_attr_spec(void)
27✔
332
{
333
   // attr_name [ = constant_expression ]
334

335
   BEGIN("attribute specification");
54✔
336

337
   (void)p_identifier();
27✔
338

339
   if (optional(tEQ))
27✔
340
      (void)p_constant_expression();
1✔
341
}
27✔
342

343
static vlog_node_t p_attribute_instance(void)
27✔
344
{
345
   // (* attr_spec { , attr_spec } *)
346

347
   BEGIN("attribute instance");
54✔
348

349
   consume(tATTRBEGIN);
27✔
350

351
   vlog_node_t v = vlog_new(V_ATTR_INST);
27✔
352

353
   do {
27✔
354
      p_attr_spec();
27✔
355
   } while (optional(tCOMMA));
27✔
356

357
   consume(tATTREND);
27✔
358

359
   vlog_set_loc(v, CURRENT_LOC);
27✔
360
   return v;
27✔
361
}
362

363
static vlog_node_t p_unsigned_number(void)
19,959✔
364
{
365
   // decimal_digit { _ | decimal_digit }
366

367
   BEGIN("unsigned number");
39,918✔
368

369
   number_t n;
19,959✔
370
   if (consume(tUNSNUM)) {
19,959✔
371
      n = number_new(state.last_lval.str, CURRENT_LOC);
19,959✔
372
      free(state.last_lval.str);
19,959✔
373
   }
374
   else
UNCOV
375
      n = number_from_int(0);
×
376

377
   vlog_node_t v = vlog_new(V_NUMBER);
19,959✔
378
   vlog_set_number(v, n);
19,959✔
379
   vlog_set_loc(v, CURRENT_LOC);
19,959✔
380
   return v;
19,959✔
381
}
382

383
static vlog_node_t p_integral_number(void)
37,216✔
384
{
385
   // decimal_number | octal_number | binary_number | hex_number
386

387
   BEGIN("integral number");
74,432✔
388

389
   if (peek() == tUNSNUM)
37,216✔
390
      return p_unsigned_number();
15,373✔
391
   else {
392
      number_t n;
21,843✔
393
      if (consume(tNUMBER)) {
21,843✔
394
         n = number_new(state.last_lval.str, &state.last_loc);
21,842✔
395
         free(state.last_lval.str);
21,842✔
396
      }
397
      else
398
         n = number_from_int(0);
1✔
399

400
      vlog_node_t v = vlog_new(V_NUMBER);
21,843✔
401
      vlog_set_number(v, n);
21,843✔
402
      vlog_set_loc(v, CURRENT_LOC);
21,843✔
403
      return v;
21,843✔
404
   }
405
}
406

407
static vlog_node_t p_real_number(void)
366✔
408
{
409
   // fixed_point_number
410
   //   | unsigned_number [ . unsigned_number ] exp [ sign ] unsigned_number
411

412
   BEGIN("real number");
732✔
413

414
   consume(tREAL);
366✔
415

416
   vlog_node_t v = vlog_new(V_REAL);
366✔
417
   vlog_set_dval(v, state.last_lval.real);
366✔
418
   vlog_set_loc(v, CURRENT_LOC);
366✔
419
   return v;
366✔
420
}
421

422
static vlog_node_t p_number(void)
37,571✔
423
{
424
   // integral_number | real_number
425

426
   BEGIN("number");
75,142✔
427

428
   if (peek() == tREAL)
37,571✔
429
      return p_real_number();
361✔
430
   else
431
      return p_integral_number();
37,210✔
432
}
433

434
static vlog_node_t p_string_literal(void)
5,987✔
435
{
436
   // " { Any_ASCII_Characters } "
437

438
   BEGIN("string literal");
11,974✔
439

440
   number_t n;
5,987✔
441
   if (consume(tSTRING)) {
5,987✔
442
      text_buf_t *tb = state.last_lval.text;
5,987✔
443
      n = number_from_string(tb_get(tb), tb_len(tb));
5,987✔
444
      tb_free(tb);
5,987✔
445
   }
446
   else
447
      should_not_reach_here();
448

449
   vlog_node_t v = vlog_new(V_STRING);
5,987✔
450
   vlog_set_number(v, n);
5,987✔
451
   vlog_set_loc(v, CURRENT_LOC);
5,987✔
452
   return v;
11,974✔
453
}
454

455
static vlog_node_t p_primary_literal(void)
43,558✔
456
{
457
   // number | time_literal | unbased_unsized_literal | string_literal
458

459
   BEGIN("primary literal");
87,116✔
460

461
   switch (peek()) {
43,558✔
462
   case tNUMBER:
37,571✔
463
   case tUNSNUM:
464
   case tREAL:
465
      return p_number();
37,571✔
466
   case tSTRING:
5,987✔
467
      return p_string_literal();
5,987✔
UNCOV
468
   default:
×
UNCOV
469
      one_of(tNUMBER, tUNSNUM, tREAL, tSTRING);
×
UNCOV
470
      return dummy_expression();
×
471
   }
472
}
473

474
static vlog_node_t p_constant_select(ident_t id)
737✔
475
{
476
   // [ { . member_identifier constant_bit_select } . member_identifier ]
477
   //    constant_bit_select [ [ constant_part_select_range ] ]
478

479
   EXTEND("constant select");
1,474✔
480

481
   // Checked for constant-ness later
482
   return p_select(id);
737✔
483
}
484

485
static vlog_node_t p_constant_expression(void)
9,478✔
486
{
487
   // constant_primary | unary_operator { attribute_instance } constant_primary
488
   //   | constant_expression binary_operator { attribute_instance }
489
   //       constant_expression
490
   //   | constant_expression ? { attribute_instance }
491
   //       constant_expression : constant_expression
492

493
   BEGIN("constant expression");
18,956✔
494

495
   // Checked for constant-ness later
496
   return p_expression();
9,478✔
497
}
498

499
static void p_constant_range(vlog_node_t *left, vlog_node_t *right)
3,868✔
500
{
501
   // constant_expression : constant_expression
502

503
   BEGIN("constant range");
7,736✔
504

505
   *left = p_constant_expression();
3,868✔
506

507
   consume(tCOLON);
3,868✔
508

509
   *right = p_constant_expression();
3,868✔
510
}
3,868✔
511

512
static vlog_node_t p_constant_range_expression(void)
2✔
513
{
514
   // constant_expression | constant_part_select_range
515

516
   BEGIN("constant range expression");
4✔
517

518
   return p_constant_expression();
2✔
519
}
520

521
static vlog_node_t p_constant_mintypmax_expression(void)
8✔
522
{
523
   // constant_expression
524
   //   | constant_expression : constant_expression : constant_expression
525

526
   return p_constant_expression();
8✔
527
}
528

529
static vlog_node_t p_packed_dimension(void)
3,783✔
530
{
531
   // [ constant_range ] | unsized_dimension
532

533
   BEGIN("packed dimension");
7,566✔
534

535
   consume(tLSQUARE);
3,783✔
536

537
   vlog_node_t left, right;
3,783✔
538
   p_constant_range(&left, &right);
3,783✔
539

540
   consume(tRSQUARE);
3,783✔
541

542
   vlog_node_t v = vlog_new(V_DIMENSION);
3,783✔
543
   vlog_set_subkind(v, V_DIM_PACKED);
3,783✔
544
   vlog_set_left(v, left);
3,783✔
545
   vlog_set_right(v, right);
3,783✔
546
   vlog_set_loc(v, CURRENT_LOC);
3,783✔
547

548
   return v;
3,783✔
549
}
550

551
static vlog_node_t p_unpacked_dimension(void)
85✔
552
{
553
   // [ constant_range ] | [ constant_expression ]
554

555
   BEGIN("unpacked dimension");
170✔
556

557
   consume(tLSQUARE);
85✔
558

559
   vlog_node_t left, right;
85✔
560
   p_constant_range(&left, &right);
85✔
561

562
   consume(tRSQUARE);
85✔
563

564
   vlog_node_t v = vlog_new(V_DIMENSION);
85✔
565
   vlog_set_subkind(v, V_DIM_UNPACKED);
85✔
566
   vlog_set_left(v, left);
85✔
567
   vlog_set_right(v, right);
85✔
568
   vlog_set_loc(v, CURRENT_LOC);
85✔
569

570
   return v;
85✔
571
}
572

573
static vlog_node_t p_data_type_or_void(void)
77✔
574
{
575
   // data_type | void
576

577
   BEGIN("data type or void");
154✔
578

579
   if (optional(tVOID))
77✔
580
      return NULL;
581
   else
582
      return p_data_type();
76✔
583
}
584

585
static void p_struct_union_member(vlog_node_t v)
60✔
586
{
587
   // { attribute_instance } [ random_qualifier ] data_type_or_void
588
   //    list_of_variable_decl_assignments ;
589

590
   BEGIN("struct or union member");
120✔
591

592
   optional_attributes();
60✔
593

594
   vlog_node_t dt = p_data_type_or_void();
60✔
595
   p_list_of_variable_decl_assignments(v, dt);
60✔
596

597
   consume(tSEMI);
60✔
598
}
60✔
599

600
static void p_enum_name_declaration(vlog_node_t parent)
73✔
601
{
602
   // enum_identifier [ [ integral_number [ : integral_number ] ] ]
603
   //   [ = constant_expression ]
604

605
   BEGIN("enum name declaration");
146✔
606

607
   vlog_node_t v = vlog_new(V_ENUM_NAME);
73✔
608
   vlog_set_ident(v, p_identifier());
73✔
609
   vlog_set_type(v, parent);
73✔
610

611
   if (optional(tEQ))
73✔
612
      vlog_set_value(v, p_constant_expression());
27✔
613

614
   vlog_add_decl(parent, v);
73✔
615

616
   vlog_set_loc(v, CURRENT_LOC);
73✔
617
   vlog_symtab_put(symtab, v);
73✔
618
}
73✔
619

620
static vlog_node_t p_integer_atom_type(void)
255✔
621
{
622
   // byte | shortint | int | longint | integer | time
623

624
   BEGIN("integer atom type");
510✔
625

626
   data_type_t dt = DT_BYTE;
255✔
627
   switch (one_of(tBYTE, tSHORTINT, tSVINT, tLONGINT, tINTEGER, tTIME)) {
255✔
628
   case tBYTE:     dt = DT_BYTE; break;
629
   case tSHORTINT: dt = DT_SHORTINT; break;
630
   case tSVINT:    dt = DT_INT; break;
631
   case tLONGINT:  dt = DT_LONGINT; break;
632
   case tINTEGER:  dt = DT_INTEGER; break;
633
   case tTIME:     dt = DT_TIME; break;
634
   }
635

636
   return make_integer_atom_type(dt);
255✔
637
}
638

639
static vlog_node_t p_integer_vector_type(void)
3,355✔
640
{
641
   //  bit | logic | reg
642

643
   BEGIN("integer vector type");
6,710✔
644

645
   data_type_t dt = DT_LOGIC;
3,355✔
646
   switch (one_of(tBIT, tLOGIC, tREG)) {
3,355✔
647
   case tBIT:    dt = DT_BIT; break;
14✔
648
   case tLOGIC:
649
   case tREG:    dt = DT_LOGIC; break;
650
   }
651

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

658
static vlog_node_t p_non_integer_type(void)
48✔
659
{
660
   // shortreal | real | realtime
661

662
   BEGIN("non-integer type");
96✔
663

664
   data_type_t dt = DT_REAL;
48✔
665
   switch (one_of(tSVREAL, tSHORTREAL, tREALTIME)) {
48✔
666
   case tSVREAL:    dt = DT_REAL; break;
667
   case tSHORTREAL: dt = DT_SHORTREAL; break;
2✔
668
   case tREALTIME:  dt = DT_REALTIME; break;
1✔
669
   }
670

671
   vlog_node_t v = vlog_new(V_DATA_TYPE);
48✔
672
   vlog_set_subkind(v, dt);
48✔
673
   vlog_set_loc(v, &state.last_loc);
48✔
674
   return v;
48✔
675
}
676

677
static vlog_node_t p_struct_union(void)
33✔
678
{
679
   // struct | union [ tagged ]
680

681
   BEGIN("struct or union");
66✔
682

683
   switch (one_of(tSTRUCT, tUNION)) {
33✔
684
   case tUNION:
11✔
685
      {
686
         vlog_node_t v = vlog_new(V_UNION_DECL);
11✔
687
         optional(tTAGGED);
11✔
688
         return v;
11✔
689
      }
690
   case tSTRUCT:
22✔
691
   default:
692
      return vlog_new(V_STRUCT_DECL);
22✔
693
   }
694
}
695

696
static vlog_flags_t p_signing(void)
129✔
697
{
698
   // signed | unsigned
699

700
   BEGIN("signing");
258✔
701

702
   switch (one_of(tSIGNED, tUNSIGNED)) {
129✔
703
   case tSIGNED: return VLOG_F_SIGNED;
704
   default: return 0;
25✔
705
   }
706
}
707

708
static vlog_node_t p_enum_base_type(void)
17✔
709
{
710
   // integer_atom_type [ signing ]
711
   //   | integer_vector_type [ signing ] [ packed_dimension ]
712
   //   | type_identifier [ packed_dimension ]
713

714
   BEGIN("enum base type");
34✔
715

716
   switch (peek()) {
17✔
717
   case tBYTE:
11✔
718
   case tSHORTINT:
719
   case tSVINT:
720
   case tLONGINT:
721
   case tINTEGER:
722
   case tTIME:
723
      {
724
         vlog_node_t v = p_integer_atom_type();
11✔
725

726
         if (scan(tSIGNED, tUNSIGNED))
11✔
UNCOV
727
            vlog_set_flags(v, p_signing());
×
728
         else
729
            vlog_set_flags(v, VLOG_F_SIGNED);
11✔
730

731
         return v;
732
      }
733

734
   case tBIT:
6✔
735
   case tLOGIC:
736
   case tREG:
737
      {
738
         vlog_node_t v = p_integer_vector_type();
6✔
739

740
         if (scan(tSIGNED, tUNSIGNED))
6✔
UNCOV
741
            vlog_set_flags(v, p_signing());
×
742

743
         if (scan(tLSQUARE))
6✔
744
            vlog_add_range(v, p_packed_dimension());
6✔
745

746
         return v;
747
      }
748

UNCOV
749
   default:
×
UNCOV
750
      return get_data_type(p_identifier());
×
751
   }
752
}
753

754
static vlog_node_t p_data_type(void)
3,762✔
755
{
756
   // integer_vector_type [ signing ] { packed_dimension }
757
   //   | integer_atom_type [ signing ] | non_integer_type
758
   //   | struct_union [ packed [ signing ] ]
759
   //       { struct_union_member { struct_union_member } } { packed_dimension }
760
   //   | enum [ enum_base_type ] { enum_name_declaration
761
   //       { , enum_name_declaration } } { packed_dimension }
762
   //   | string | chandle
763
   //   | virtual [ interface ] interface_identifier
764
   //       [ parameter_value_assignment ] [ . modport_identifier ]
765
   //   | [ class_scope | package_scope ] type_identifier { packed_dimension }
766
   //   | class_type | event | ps_covergroup_identifier | type_reference
767

768
   BEGIN("data type");
7,524✔
769

770
   switch (peek()) {
3,762✔
771
   case tBIT:
3,349✔
772
   case tLOGIC:
773
   case tREG:
774
      {
775
         vlog_node_t v = p_integer_vector_type();
3,349✔
776

777
         if (scan(tSIGNED, tUNSIGNED))
3,349✔
778
            vlog_set_flags(v, p_signing());
65✔
779

780
         while (peek() == tLSQUARE)
6,198✔
781
            vlog_add_range(v, p_packed_dimension());
2,849✔
782

783
         return v;
784
      }
785

786
   case tBYTE:
244✔
787
   case tSHORTINT:
788
   case tSVINT:
789
   case tLONGINT:
790
   case tINTEGER:
791
   case tTIME:
792
      {
793
         vlog_node_t v = p_integer_atom_type();
244✔
794

795
         if (scan(tSIGNED, tUNSIGNED))
244✔
796
            vlog_set_flags(v, p_signing());
1✔
797
         else
798
            vlog_set_flags(v, VLOG_F_SIGNED);
243✔
799

800
         return v;
801
      }
802

803
   case tSVREAL:
48✔
804
   case tREALTIME:
805
   case tSHORTREAL:
806
      return p_non_integer_type();
48✔
807

808
   case tSTRUCT:
33✔
809
   case tUNION:
810
      {
811
         vlog_node_t v = p_struct_union();
33✔
812

813
         if (optional(tPACKED)) {
33✔
814
            vlog_set_flags(v, VLOG_F_PACKED);
26✔
815

816
            if (scan(tSIGNED, tUNSIGNED))
26✔
UNCOV
817
               vlog_set_flags(v, p_signing());
×
818
         }
819

820
         consume(tLBRACE);
33✔
821

822
         vlog_symtab_push(symtab, v);
33✔
823

824
         do {
60✔
825
            p_struct_union_member(v);
60✔
826
         } while (not_at_token(tRBRACE));
60✔
827

828
         vlog_symtab_pop(symtab);
33✔
829

830
         consume(tRBRACE);
33✔
831

832
         if (peek() == tLSQUARE)
33✔
UNCOV
833
            vlog_add_range(v, p_packed_dimension());
×
834

835
         vlog_set_loc(v, CURRENT_LOC);
33✔
836
         return v;
33✔
837
      }
838

839
   case tENUM:
26✔
840
      {
841
         consume(tENUM);
26✔
842

843
         vlog_node_t v = vlog_new(V_ENUM_DECL);
26✔
844

845
         if (peek() != tLBRACE)
26✔
846
            vlog_set_type(v, p_enum_base_type());
17✔
847
         else {
848
            vlog_node_t dt = make_integer_atom_type(DT_INT);
9✔
849
            vlog_set_flags(dt, VLOG_F_SIGNED);
9✔
850

851
            vlog_set_type(v, dt);
9✔
852
         }
853

854
         consume(tLBRACE);
26✔
855

856
         do {
73✔
857
            p_enum_name_declaration(v);
73✔
858
         } while (optional(tCOMMA));
73✔
859

860
         consume(tRBRACE);
26✔
861

862
         while (peek() == tLSQUARE)
28✔
863
            vlog_add_range(v, p_packed_dimension());
2✔
864

865
         vlog_set_loc(v, CURRENT_LOC);
26✔
866
         return v;
26✔
867
      }
868

869
   case tEVENT:
1✔
870
      {
871
         consume(tEVENT);
1✔
872

873
         vlog_node_t v = vlog_new(V_DATA_TYPE);
1✔
874
         vlog_set_subkind(v, DT_EVENT);
1✔
875
         vlog_set_loc(v, &state.last_loc);
1✔
876

877
         return v;
1✔
878
      }
879

880
   case tID:
57✔
881
      return get_data_type(p_identifier());
57✔
882

883
   case tSTRINGK:
4✔
884
      {
885
         consume(tSTRINGK);
4✔
886

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

891
         return v;
4✔
892
      }
893

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

902
static vlog_node_t p_implicit_data_type(void)
1,856✔
903
{
904
   // [ signing ] { packed_dimension }
905

906
   BEGIN("implicit data type");
3,712✔
907

908
   vlog_node_t v = vlog_new(V_DATA_TYPE);
1,856✔
909
   vlog_set_subkind(v, DT_IMPLICIT);
1,856✔
910

911
   if (scan(tSIGNED, tUNSIGNED))
1,856✔
912
      vlog_set_flags(v, p_signing());
63✔
913

914
   while (peek() == tLSQUARE)
2,781✔
915
      vlog_add_range(v, p_packed_dimension());
925✔
916

917
   vlog_set_loc(v, CURRENT_LOC);
1,856✔
918
   return v;
1,856✔
919
}
920

921
static vlog_node_t p_data_type_or_implicit(void)
5,422✔
922
{
923
   // data_type | implicit_data_type
924

925
   BEGIN("data type or implicit");
10,844✔
926

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

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

962
   BEGIN("net port type");
1,082✔
963

964
   if (scan(tSUPPLY0, tSUPPLY1, tTRI, tTRIAND, tTRIOR, tTRIREG,
541✔
965
            tTRI0, tTRI1, tUWIRE, tWIRE, tWAND, tWOR))
966
      *kind = p_net_type();
86✔
967
   else
968
      *kind = V_NET_WIRE;
455✔
969

970
   *dt = p_data_type_or_implicit();
541✔
971
}
541✔
972

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

977
   BEGIN("var data type");
48✔
978

979
   return p_data_type();
24✔
980
}
981

982
static vlog_node_t p_variable_port_type(void)
24✔
983
{
984
   // var_data_type
985

986
   BEGIN("variable port type");
48✔
987

988
   return p_var_data_type();
24✔
989
}
990

991
static void p_list_of_port_identifiers(vlog_node_t mod, v_port_kind_t kind,
408✔
992
                                       vlog_node_t datatype)
993
{
994
   // port_identifier { unpacked_dimension }
995
   //    { , port_identifier { unpacked_dimension } }
996

997
   BEGIN("list of port identifiers");
816✔
998

999
   do {
436✔
1000
      ident_t id, ext;
436✔
1001
      p_external_identifier(&id, &ext);
436✔
1002

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

1010
      vlog_add_decl(mod, v);
436✔
1011
      vlog_symtab_put(symtab, v);
436✔
1012

1013
      declare_port(mod, v);
436✔
1014
   } while (optional(tCOMMA));
436✔
1015
}
408✔
1016

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

1024
   BEGIN("list of variable port identifiers");
48✔
1025

1026
   do {
24✔
1027
      ident_t id, ext;
24✔
1028
      p_external_identifier(&id, &ext);
24✔
1029

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

1037
      if (optional(tEQ))
24✔
1038
         vlog_set_value(v, p_constant_expression());
4✔
1039

1040
      vlog_add_decl(mod, v);
24✔
1041
      vlog_symtab_put(symtab, v);
24✔
1042

1043
      declare_port(mod, v);
24✔
1044
   } while (optional(tCOMMA));
24✔
1045
}
24✔
1046

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

1051
   BEGIN("inout declaration");
2✔
1052

1053
   consume(tINOUT);
1✔
1054

1055
   vlog_node_t dt;
1✔
1056
   vlog_net_kind_t kind;
1✔
1057
   p_net_port_type(&kind, &dt);
1✔
1058

1059
   p_list_of_port_identifiers(mod, V_PORT_INOUT, dt);
1✔
1060
}
1✔
1061

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

1067
   BEGIN("input declaration");
466✔
1068

1069
   consume(tINPUT);
233✔
1070

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

1085
static void p_output_declaration(vlog_node_t mod)
198✔
1086
{
1087
   // output net_port_type list_of_port_identifiers
1088
   //   | output variable_port_type list_of_variable_port_identifiers
1089

1090
   BEGIN("output declaration");
396✔
1091

1092
   consume(tOUTPUT);
198✔
1093

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

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

1120
   BEGIN("port declaration");
864✔
1121

1122
   switch (peek()) {
432✔
1123
   case tINOUT: p_inout_declaration(mod); break;
1✔
1124
   case tINPUT: p_input_declaration(mod); break;
233✔
1125
   case tOUTPUT: p_output_declaration(mod); break;
198✔
1126
   default: should_not_reach_here();
1127
   }
1128
}
432✔
1129

1130
static void p_net_port_header(v_port_kind_t *dir, vlog_node_t *dt)
133✔
1131
{
1132
   // [ port_direction ] net_port_type
1133

1134
   BEGIN("net port header");
266✔
1135

1136
   if (optional(tINPUT))
133✔
1137
      *dir = V_PORT_INPUT;
72✔
1138
   else if (optional(tINOUT))
61✔
UNCOV
1139
      *dir = V_PORT_INOUT;
×
1140
   else if (optional(tOUTPUT))
61✔
1141
      *dir = V_PORT_OUTPUT;
61✔
1142

1143
   vlog_net_kind_t kind;
133✔
1144
   p_net_port_type(&kind, dt);
133✔
1145
}
133✔
1146

1147
static void p_part_select_range(vlog_node_t ps)
1,577✔
1148
{
1149
   // constant_expression : constant_expression
1150
   //   | expression +: constant_expression
1151
   //   | expression -: constant_expression
1152

1153
   BEGIN("part select range");
3,154✔
1154

1155
   vlog_range_kind_t kind = V_RANGE_CONST;
1,577✔
1156
   switch (one_of(tCOLON, tINDEXPOS, tINDEXNEG)) {
1,577✔
1157
   case tINDEXPOS: kind = V_RANGE_POS; break;
641✔
1158
   case tINDEXNEG: kind = V_RANGE_NEG; break;
608✔
1159
   }
1160

1161
   vlog_set_subkind(ps, kind);
1,577✔
1162
   vlog_set_right(ps, p_constant_expression());
1,577✔
1163
}
1,577✔
1164

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

1169
   EXTEND("hierarchical identifier");
20✔
1170

1171
   if (id == NULL)
10✔
1172
      id = p_identifier();
3✔
1173

1174
   vlog_node_t v = vlog_new(V_HIER_REF);
10✔
1175
   vlog_set_ident(v, id);
10✔
1176

1177
   consume(tDOT);
10✔
1178

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

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

1190
static vlog_node_t p_select(ident_t id)
40,275✔
1191
{
1192
   // [ { . member_identifier bit_select } . member_identifier ]
1193
   //    { [ expression ] } [ [ part_select_range ] ]
1194

1195
   EXTEND("select");
80,550✔
1196

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

1209
      vlog_symtab_lookup(symtab, prefix);
40,268✔
1210

1211
      while (optional(tDOT)) {
40,509✔
1212
         vlog_node_t ref = vlog_new(V_MEMBER_REF);
241✔
1213
         vlog_set_ident(ref, p_identifier());
241✔
1214
         vlog_set_value(ref, prefix);
241✔
1215
         vlog_set_loc(ref, CURRENT_LOC);
241✔
1216

1217
         vlog_symtab_lookup(symtab, ref);
241✔
1218

1219
         prefix = ref;
241✔
1220
      }
1221
   }
1222

1223
   if (optional(tLSQUARE)) {
40,275✔
1224
      do {
2,543✔
1225
         vlog_node_t expr = p_expression();
2,543✔
1226
         if (scan(tCOLON, tINDEXPOS, tINDEXNEG)) {
2,543✔
1227
            vlog_node_t ps = vlog_new(V_PART_SELECT);
1,577✔
1228
            vlog_set_left(ps, expr);
1,577✔
1229
            vlog_set_value(ps, prefix);
1,577✔
1230

1231
            p_part_select_range(ps);
1,577✔
1232

1233
            consume(tRSQUARE);
1,577✔
1234

1235
            vlog_set_loc(ps, CURRENT_LOC);
1,577✔
1236
            return ps;
1,577✔
1237
         }
1238

1239
         if (vlog_kind(prefix) == V_BIT_SELECT)
966✔
1240
            vlog_add_param(prefix, expr);
84✔
1241
         else {
1242
            vlog_node_t bs = vlog_new(V_BIT_SELECT);
882✔
1243
            vlog_set_loc(bs, CURRENT_LOC);
882✔
1244
            vlog_set_value(bs, prefix);
882✔
1245
            vlog_add_param(bs, expr);
882✔
1246

1247
            prefix = bs;
882✔
1248
         }
1249

1250
         consume(tRSQUARE);
966✔
1251
      } while (optional(tLSQUARE));
966✔
1252
   }
1253

1254
   return prefix;
1255
}
1256

1257
static void p_list_of_arguments(vlog_node_t call)
6,348✔
1258
{
1259
   // [ expression ] { , [ expression ] } { , . identifier ( [ expression ] ) }
1260
   //    | . identifier ( [ expression ] ) { , . identifier ( [ expression ] ) }
1261

1262
   BEGIN("list of arguments");
12,696✔
1263

1264
   if (peek() == tRPAREN)
6,348✔
1265
      return;
63✔
1266

1267
   do {
13,153✔
1268
      if (peek() == tCOMMA) {
13,153✔
1269
         vlog_node_t v = vlog_new(V_EMPTY);
280✔
1270
         vlog_set_loc(v, &state.last_loc);
280✔
1271
         vlog_add_param(call, v);
280✔
1272
      }
1273
      else
1274
         vlog_add_param(call, p_expression());
12,873✔
1275
   } while (optional(tCOMMA));
13,153✔
1276
}
1277

1278
static vlog_node_t p_system_tf_call(vlog_kind_t kind)
9,364✔
1279
{
1280
   // system_tf_identifier [ ( list_of_arguments ) ]
1281

1282
   BEGIN("system task or function call");
18,728✔
1283

1284
   vlog_node_t v = vlog_new(kind);
9,364✔
1285
   vlog_set_ident(v, p_system_tf_identifier());
9,364✔
1286

1287
   if (optional(tLPAREN)) {
9,364✔
1288
      p_list_of_arguments(v);
5,965✔
1289
      consume(tRPAREN);
5,965✔
1290
   }
1291

1292
   vlog_set_loc(v, CURRENT_LOC);
9,364✔
1293
   return v;
9,364✔
1294
}
1295

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

1301
   BEGIN("task or function call");
774✔
1302

1303
   vlog_node_t v = vlog_new(kind);
387✔
1304
   vlog_set_ident(v, p_identifier());
387✔
1305

1306
   optional_attributes();
387✔
1307

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

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

1318
static vlog_node_t p_subroutine_call(vlog_kind_t kind)
9,751✔
1319
{
1320
   // tf_call | system_tf_call | method_call | [ std:: ] randomize_call
1321

1322
   BEGIN("subroutine call");
19,502✔
1323

1324
   if (peek() == tSYSTASK)
9,751✔
1325
      return p_system_tf_call(kind);
9,364✔
1326
   else
1327
      return p_tf_call(kind);
387✔
1328
}
1329

1330
static vlog_node_t p_mintypmax_expression(void)
43,941✔
1331
{
1332
   // expression | expression : expression : expression
1333

1334
   BEGIN("mintypmax expression");
87,882✔
1335

1336
   vlog_node_t e = p_expression();
43,941✔
1337

1338
   if (optional(tCOLON)) {
43,941✔
1339
      vlog_node_t mtm = vlog_new(V_MIN_TYP_MAX);
1✔
1340
      vlog_set_left(mtm, e);
1✔
1341
      vlog_set_value(mtm, p_expression());
1✔
1342

1343
      consume(tCOLON);
1✔
1344
      vlog_set_right(mtm, p_expression());
1✔
1345

1346
      return mtm;
1✔
1347
   }
1348

1349
   return e;
1350
}
1351

1352
static vlog_node_t p_concatenation(vlog_node_t head)
301✔
1353
{
1354
   // { expression { , expression } }
1355

1356
   BEGIN_WITH_HEAD("concatenation", head);
602✔
1357

1358
   if (head == NULL) {
301✔
1359
      consume(tLBRACE);
93✔
1360
      head = p_expression();
93✔
1361
   }
1362

1363
   vlog_node_t v = vlog_new(V_CONCAT);
301✔
1364
   vlog_add_param(v, head);
301✔
1365

1366
   while (optional(tCOMMA))
675✔
1367
      vlog_add_param(v, p_expression());
374✔
1368

1369
   consume(tRBRACE);
301✔
1370

1371
   vlog_set_loc(v, CURRENT_LOC);
301✔
1372
   return v;
301✔
1373
}
1374

1375
static vlog_node_t p_multiple_concatenation(vlog_node_t head)
93✔
1376
{
1377
   // { expression concatenation }
1378

1379
   BEGIN_WITH_HEAD("multiple concatenation", head);
186✔
1380

1381
   vlog_node_t v = p_concatenation(NULL);
93✔
1382
   vlog_set_value(v, head);
93✔
1383

1384
   consume(tRBRACE);
93✔
1385

1386
   vlog_set_loc(v, CURRENT_LOC);
93✔
1387
   return v;
93✔
1388
}
1389

1390
static vlog_node_t p_package_identifier(void)
3✔
1391
{
1392
   // identifier
1393

1394
   BEGIN("package identifier");
6✔
1395

1396
   ident_t id = p_identifier();
3✔
1397

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

1408
   return v;
1409
}
1410

UNCOV
1411
static vlog_node_t p_package_scope(void)
×
1412
{
1413
   // package_identifier :: | $unit ::
1414

1415
   BEGIN("package scope");
×
1416

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

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

1441
   BEGIN("primary");
238,338✔
1442

1443
   switch (peek()) {
119,169✔
1444
   case tID:
28,862✔
1445
      switch (peek_nth(2)) {
28,862✔
1446
      case tLPAREN:
258✔
1447
      case tATTRBEGIN:
1448
         return p_subroutine_call(V_USER_FCALL);
258✔
UNCOV
1449
      case tSCOPE:
×
UNCOV
1450
         p_package_scope();
×
1451
      default:
28,604✔
1452
         return p_select(p_identifier());
28,604✔
1453
      }
1454
   case tSTRING:
43,558✔
1455
   case tNUMBER:
1456
   case tUNSNUM:
1457
   case tREAL:
1458
      return p_primary_literal();
43,558✔
1459
   case tSYSTASK:
2,894✔
1460
      return p_subroutine_call(V_SYS_FCALL);
2,894✔
1461
   case tLPAREN:
43,536✔
1462
      {
1463
         consume(tLPAREN);
43,536✔
1464
         vlog_node_t expr = p_mintypmax_expression();
43,536✔
1465
         consume(tRPAREN);
43,536✔
1466
         return expr;
43,536✔
1467
      }
1468
   case tLBRACE:
301✔
1469
      {
1470
         consume(tLBRACE);
301✔
1471

1472
         vlog_node_t head = p_expression();
301✔
1473
         if (peek() == tLBRACE)
301✔
1474
            return p_multiple_concatenation(head);
93✔
1475
         else
1476
            return p_concatenation(head);
208✔
1477
      }
1478
   case tNULL:
18✔
1479
      {
1480
         consume(tNULL);
18✔
1481

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

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

1494
static vlog_binary_t p_binary_operator(void)
30,929✔
1495
{
1496
   // + | - | * | / | % | == | != | === | !== | ==? | !=? | && | ||
1497
   //  | ** | < | <= | > | >= | & | | | ^ | ^~ | ~^ | >> | <<
1498
   //  | >>> | <<< | -> | <->
1499

1500
   BEGIN("binary operator");
61,858✔
1501

1502
   switch (one_of(tBAR, tPLUS, tAMP, tCASEEQ, tCASENEQ, tLOGOR,
30,929✔
1503
                  tLOGEQ, tLOGNEQ, tDBLAMP, tSHIFTLL, tSHIFTRL,
1504
                  tSHIFTLA, tSHIFTRA, tLT, tGT, tLE, tGE, tMINUS,
1505
                  tTIMES, tOVER, tPERCENT, tPOWER, tCARET, tTILDECARET,
1506
                  tTILDEAMP, tTILDEBAR)) {
1507
   case tBAR:        return V_BINARY_OR;
1508
   case tAMP:        return V_BINARY_AND;
1,252✔
1509
   case tCASEEQ:     return V_BINARY_CASE_EQ;
1,531✔
1510
   case tCASENEQ:    return V_BINARY_CASE_NEQ;
3,861✔
1511
   case tLOGEQ:      return V_BINARY_LOG_EQ;
1,740✔
1512
   case tLOGNEQ:     return V_BINARY_LOG_NEQ;
1,676✔
1513
   case tLOGOR:      return V_BINARY_LOG_OR;
2,270✔
1514
   case tDBLAMP:     return V_BINARY_LOG_AND;
1,518✔
1515
   case tSHIFTLL:    return V_BINARY_SHIFT_LL;
42✔
1516
   case tSHIFTRL:    return V_BINARY_SHIFT_RL;
32✔
1517
   case tSHIFTLA:    return V_BINARY_SHIFT_LA;
10✔
1518
   case tSHIFTRA:    return V_BINARY_SHIFT_RA;
27✔
1519
   case tLT:         return V_BINARY_LT;
1,369✔
1520
   case tGT:         return V_BINARY_GT;
1,409✔
1521
   case tLE:         return V_BINARY_LEQ;
1,400✔
1522
   case tGE:         return V_BINARY_GEQ;
1,436✔
1523
   case tMINUS:      return V_BINARY_MINUS;
1,777✔
1524
   case tTIMES:      return V_BINARY_TIMES;
1,365✔
1525
   case tOVER:       return V_BINARY_DIVIDE;
1,332✔
1526
   case tPERCENT:    return V_BINARY_MOD;
1,330✔
1527
   case tPOWER:      return V_BINARY_EXP;
17✔
1528
   case tCARET:      return V_BINARY_XOR;
1,211✔
1529
   case tTILDECARET: return V_BINARY_XNOR;
6✔
1530
   case tTILDEAMP:   return V_BINARY_NAND;
16✔
1531
   case tTILDEBAR:   return V_BINARY_NOR;
20✔
1532
   case tPLUS:
2,741✔
1533
   default:          return V_BINARY_PLUS;
2,741✔
1534
   }
1535
}
1536

1537
static vlog_unary_t p_unary_operator(void)
9,267✔
1538
{
1539
   // + | - | ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~
1540

1541
   BEGIN("unary operator");
18,534✔
1542

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

1559
static vlog_incdec_t p_inc_or_dec_operator(void)
42✔
1560
{
1561
   // ++ | --
1562

1563
   BEGIN("inc or dec operator");
84✔
1564

1565
   switch (one_of(tPLUSPLUS, tMINUSMINUS)) {
42✔
1566
   case tMINUSMINUS: return V_INCDEC_MINUS;
1567
   case tPLUSPLUS:
41✔
1568
   default: return V_INCDEC_PLUS;
41✔
1569
   }
1570
}
1571

1572
static vlog_node_t p_inc_or_dec_expression(vlog_node_t head)
40✔
1573
{
1574
   // inc_or_dec_operator { attribute_instance } variable_lvalue
1575
   //   | variable_lvalue { attribute_instance } inc_or_dec_operator
1576

1577
   BEGIN_WITH_HEAD("inc or dec expression", head);
80✔
1578

1579
   vlog_node_t v = vlog_new(head ? V_POSTFIX : V_PREFIX);
46✔
1580
   vlog_set_subkind(v, p_inc_or_dec_operator());
40✔
1581
   vlog_set_target(v, head ?: p_variable_lvalue());
40✔
1582

1583
   vlog_set_loc(v, CURRENT_LOC);
40✔
1584
   return v;
40✔
1585
}
1586

1587
static vlog_node_t p_nonbinary_expression(void)
119,175✔
1588
{
1589
   // primary | unary_operator { attribute_instance } primary
1590
   //   | inc_or_dec_expression | ( operator_assignment )
1591
   //   | conditional_expression | inside_expression | tagged_union_expression
1592

1593
   switch (peek()) {
119,175✔
1594
   case tID:
109,902✔
1595
   case tSTRING:
1596
   case tNUMBER:
1597
   case tUNSNUM:
1598
   case tREAL:
1599
   case tSYSTASK:
1600
   case tLPAREN:
1601
   case tLBRACE:
1602
   case tNULL:
1603
      return p_primary();
109,902✔
1604
   case tMINUS:
9,267✔
1605
   case tPLUS:
1606
   case tTILDE:
1607
   case tBANG:
1608
   case tAMP:
1609
   case tBAR:
1610
   case tCARET:
1611
   case tTILDEAMP:
1612
   case tTILDEBAR:
1613
   case tTILDECARET:
1614
      {
1615
         vlog_node_t v = vlog_new(V_UNARY);
9,267✔
1616
         vlog_set_subkind(v, p_unary_operator());
9,267✔
1617

1618
         optional_attributes();
9,267✔
1619

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

1635
static vlog_node_t p_conditional_expression(vlog_node_t head)
1,498✔
1636
{
1637
   // cond_predicate ? { attribute_instance } expression : expression
1638

1639
   BEGIN_WITH_HEAD("conditional expression", head);
2,996✔
1640

1641
   vlog_node_t v = vlog_new(V_COND_EXPR);
1,498✔
1642
   vlog_set_value(v, head);
1,498✔
1643

1644
   consume(tQUESTION);
1,498✔
1645

1646
   optional_attributes();
1,498✔
1647

1648
   vlog_set_left(v, p_expression());
1,498✔
1649

1650
   consume(tCOLON);
1,498✔
1651

1652
   vlog_set_right(v, p_expression());
1,498✔
1653

1654
   vlog_set_loc(v, CURRENT_LOC);
1,498✔
1655
   return v;
1,498✔
1656
}
1657

1658
static bool peek_binary_operator(int *prec)
154,052✔
1659
{
1660
   // See LRM 1800-2017 section 11.3.2 for operator precedence table
1661

1662
   switch (peek()) {
154,052✔
1663
   case tPOWER:      *prec = 12; return true;
21✔
1664
   case tTIMES:
4,039✔
1665
   case tOVER:
1666
   case tPERCENT:    *prec = 11; return true;
4,039✔
1667
   case tPLUS:
4,562✔
1668
   case tMINUS:      *prec = 10; return true;
4,562✔
1669
   case tSHIFTLL:
113✔
1670
   case tSHIFTRL:
1671
   case tSHIFTLA:
1672
   case tSHIFTRA:    *prec = 9;  return true;
113✔
1673
   case tLT:
5,642✔
1674
   case tGT:
1675
   case tLE:
1676
   case tGE:         *prec = 8;  return true;
5,642✔
1677
   case tCASEEQ:
9,996✔
1678
   case tCASENEQ:
1679
   case tLOGEQ:
1680
   case tLOGNEQ:     *prec = 7;  return true;
9,996✔
1681
   case tTILDEAMP:
1,270✔
1682
   case tAMP:        *prec = 6;  return true;
1,270✔
1683
   case tTILDECARET:
1,217✔
1684
   case tCARET:      *prec = 5;  return true;
1,217✔
1685
   case tTILDEBAR:
1,562✔
1686
   case tBAR:        *prec = 4;  return true;
1,562✔
1687
   case tDBLAMP:     *prec = 3;  return true;
1,806✔
1688
   case tLOGOR:      *prec = 2;  return true;
4,603✔
1689
   case tQUESTION:   *prec = 1;  return true;
1,508✔
1690
   default:
1691
      return false;
1692
   }
1693
}
1694

1695
static vlog_node_t p_binary_expression(vlog_node_t lhs, int min_prec)
89,471✔
1696
{
1697
   // Precedence climbing method, see
1698
   //    https://en.wikipedia.org/wiki/Operator-precedence_parser
1699

1700
   int prec1;
89,471✔
1701
   while (peek_binary_operator(&prec1) && prec1 >= min_prec) {
121,898✔
1702
      if (peek() == tQUESTION)
32,427✔
1703
         lhs = p_conditional_expression(lhs);
1,498✔
1704
      else {
1705
         vlog_node_t v = vlog_new(V_BINARY);
30,929✔
1706
         vlog_set_subkind(v, p_binary_operator());
30,929✔
1707
         vlog_set_left(v, lhs);
30,929✔
1708

1709
         optional_attributes();
30,929✔
1710

1711
         vlog_node_t rhs = p_nonbinary_expression();
30,929✔
1712

1713
         int prec2;
30,929✔
1714
         while (peek_binary_operator(&prec2) && prec2 > prec1)
32,154✔
1715
            rhs = p_binary_expression(rhs, prec1 + (prec2 > prec1));
1,225✔
1716

1717
         vlog_set_right(v, rhs);
30,929✔
1718
         vlog_set_loc(v, CURRENT_LOC);
30,929✔
1719
         lhs = v;
30,929✔
1720
      }
1721
   }
1722

1723
   return lhs;
89,471✔
1724
}
1725

1726
static vlog_node_t p_expression(void)
88,246✔
1727
{
1728
   // primary | unary_operator { attribute_instance } primary
1729
   //   | inc_or_dec_expression | ( operator_assignment )
1730
   //   | expression binary_operator { attribute_instance } expression
1731
   //   | conditional_expression | inside_expression | tagged_union_expression
1732

1733
   BEGIN("expression");
176,492✔
1734

1735
   vlog_node_t head = p_nonbinary_expression();
88,246✔
1736
   return p_binary_expression(head, 0);
88,246✔
1737
}
1738

1739
static void p_event_expression(vlog_node_t ctrl)
265✔
1740
{
1741
   // [ edge_identifier ] expression [ iff expression ]
1742
   //   | sequence_instance [ iff expression ]
1743
   //   | event_expression or event_expression
1744
   //   | event_expression , event_expression
1745
   //   | ( event_expression )
1746

1747
   BEGIN("event expression");
530✔
1748

1749
   do {
299✔
1750
      if (optional(tLPAREN)) {
299✔
1751
         p_event_expression(ctrl);
1✔
1752
         consume(tRPAREN);
1✔
1753
      }
1754
      else {
1755
         vlog_node_t v = vlog_new(V_EVENT);
298✔
1756

1757
         if (optional(tPOSEDGE))
298✔
1758
            vlog_set_subkind(v, V_EVENT_POSEDGE);
97✔
1759
         else if (optional(tNEGEDGE))
201✔
1760
            vlog_set_subkind(v, V_EVENT_NEGEDGE);
44✔
1761
         else
1762
            vlog_set_subkind(v, V_EVENT_LEVEL);
157✔
1763

1764
         vlog_set_value(v, p_expression());
298✔
1765
         vlog_set_loc(v, CURRENT_LOC);
298✔
1766

1767
         vlog_add_param(ctrl, v);
298✔
1768
      }
1769
   } while (optional(tOR) || optional(tCOMMA));
299✔
1770
}
265✔
1771

1772
static vlog_node_t p_cond_predicate(void)
2,309✔
1773
{
1774
   // expression_or_cond_pattern { &&& expression_or_cond_pattern }
1775

1776
   BEGIN("cond predicate");
4,618✔
1777

1778
   return p_expression();
2,309✔
1779
}
1780

1781
static vlog_node_t p_event_control(void)
339✔
1782
{
1783
   // @ hierarchical_event_identifier | @ ( event_expression )
1784
   //    | @* | @ (*) | @ ps_or_hierarchical_sequence_identifier
1785

1786
   BEGIN("event control");
678✔
1787

1788
   consume(tAT);
339✔
1789

1790
   vlog_node_t v = vlog_new(V_EVENT_CONTROL);
339✔
1791

1792
   switch (one_of(tLPAREN, tTIMES, tPARENSTAR)) {
339✔
1793
   case tLPAREN:
265✔
1794
      if (peek() == tATTREND)
265✔
1795
         consume(tATTREND);   // Lexing ambiguity
1✔
1796
      else {
1797
         p_event_expression(v);
264✔
1798
         consume(tRPAREN);
264✔
1799
      }
1800
      break;
1801
   case tTIMES:
1802
   case tPARENSTAR:
1803
      break;
1804
   }
1805

1806
   vlog_set_loc(v, CURRENT_LOC);
339✔
1807
   return v;
339✔
1808
}
1809

1810
static vlog_node_t p_delay_value(void)
4,592✔
1811
{
1812
   // unsigned_number | real_number | ps_identifier | time_literal | 1step
1813

1814
   BEGIN("delay value");
9,184✔
1815

1816
   switch (peek()) {
4,592✔
1817
   case tREAL:
5✔
1818
      return p_real_number();
5✔
1819
   case tID:
1✔
1820
      {
1821
         vlog_node_t v = vlog_new(V_REF);
1✔
1822
         vlog_set_ident(v, p_identifier());
1✔
1823
         vlog_set_loc(v, CURRENT_LOC);
1✔
1824

1825
         vlog_symtab_lookup(symtab, v);
1✔
1826
         return v;
1✔
1827
      }
1828
   case tUNSNUM:
4,586✔
1829
   default:
1830
      return p_unsigned_number();
4,586✔
1831
   }
1832
}
1833

1834
static vlog_node_t p_delay_control(void)
4,591✔
1835
{
1836
   // # delay_value | # ( mintypmax_expression )
1837

1838
   BEGIN("delay control");
9,182✔
1839

1840
   consume(tHASH);
4,591✔
1841

1842
   vlog_node_t v = vlog_new(V_DELAY_CONTROL);
4,591✔
1843

1844
   if (peek() != tLPAREN)
4,591✔
1845
      vlog_set_value(v, p_delay_value());
4,587✔
1846
   else
1847
      vlog_set_value(v, p_mintypmax_expression());
4✔
1848

1849
   vlog_set_loc(v, CURRENT_LOC);
4,591✔
1850
   return v;
4,591✔
1851
}
1852

1853
static void p_delay3(void)
7✔
1854
{
1855
   // # delay_value | # ( mintypmax_expression [ , mintypmax_expression
1856
   //   [ , mintypmax_expression ] ] )
1857

1858
   BEGIN("delay3");
14✔
1859

1860
   consume(tHASH);
7✔
1861

1862
   if (peek() != tLPAREN)
7✔
1863
      p_delay_value();
3✔
1864
   else {
1865
      consume(tLPAREN);
4✔
1866

1867
      int expr_cnt = 0;
4✔
1868
      do {
12✔
1869
         (void)p_mintypmax_expression();
12✔
1870
         expr_cnt++;
12✔
1871
      } while (optional(tCOMMA) && (expr_cnt < 3));
12✔
1872

1873
      consume(tRPAREN);
4✔
1874
   }
1875
}
7✔
1876

1877
static void p_delay2(void)
2✔
1878
{
1879
   // # delay_value | # ( mintypmax_expression [ , mintypmax_expression ] )
1880

1881
   BEGIN("delay2");
4✔
1882

1883
   consume(tHASH);
2✔
1884

1885
   if (peek() != tLPAREN)
2✔
1886
      p_delay_value();
1✔
1887
   else {
1888
      consume(tLPAREN);
1✔
1889

1890
      (void)p_mintypmax_expression();
1✔
1891

1892
      if (optional(tCOMMA))
1✔
1893
         (void)p_mintypmax_expression();
1✔
1894

1895
      consume(tRPAREN);
1✔
1896
   }
1897
}
2✔
1898

1899
static vlog_node_t p_delay_or_event_control(void)
50✔
1900
{
1901
   // delay_control | event_control | repeat ( expression ) event_control
1902

1903
   BEGIN("delay or event control");
100✔
1904

1905
   return p_delay_control();
50✔
1906
}
1907

1908
static vlog_node_t p_variable_lvalue(void)
10,938✔
1909
{
1910
   // [ implicit_class_handle . | package_scope ]
1911
   //      hierarchical_variable_identifier select
1912
   //   | { variable_lvalue { , variable_lvalue } }
1913
   //   | [ assignment_pattern_expression_type ]
1914
   //      assignment_pattern_variable_lvalue
1915
   //   | streaming_concatenation
1916

1917
   BEGIN("variable lvalue");
21,876✔
1918

1919
   if (optional(tLBRACE)) {
10,938✔
1920
      vlog_node_t v = vlog_new(V_CONCAT);
5✔
1921

1922
      do {
14✔
1923
         vlog_add_param(v, p_variable_lvalue());
14✔
1924
      } while (optional(tCOMMA));
14✔
1925

1926
      consume(tRBRACE);
5✔
1927

1928
      vlog_set_loc(v, CURRENT_LOC);
5✔
1929
      return v;
5✔
1930
   }
1931
   else {
1932
      ident_t id = p_identifier();
10,933✔
1933
      vlog_node_t v = p_select(id);
10,933✔
1934

1935
      vlog_set_loc(v, CURRENT_LOC);
10,933✔
1936
      return v;
10,933✔
1937
   }
1938
}
1939

1940
static vlog_node_t p_net_lvalue(void)
748✔
1941
{
1942
   // ps_or_hierarchical_net_identifier constant_select
1943
   //   | { net_lvalue { , net_lvalue } }
1944
   //   | [ assignment_pattern_expression_type ] assignment_pattern_net_lvalue
1945

1946
   BEGIN("net lvalue");
1,496✔
1947

1948
   if (optional(tLBRACE)) {
748✔
1949
      vlog_node_t v = vlog_new(V_CONCAT);
11✔
1950

1951
      do {
22✔
1952
         vlog_add_param(v, p_net_lvalue());
22✔
1953
      } while (optional(tCOMMA));
22✔
1954

1955
      consume(tRBRACE);
11✔
1956

1957
      vlog_set_loc(v, CURRENT_LOC);
11✔
1958
      return v;
11✔
1959
   }
1960
   else {
1961
      ident_t id = p_identifier();
737✔
1962
      vlog_node_t v = p_constant_select(id);
737✔
1963

1964
      vlog_set_loc(v, CURRENT_LOC);
737✔
1965
      return v;
737✔
1966
   }
1967
}
1968

1969
static vlog_node_t p_class_new(vlog_node_t dt)
8✔
1970
{
1971
   // [ class_scope ] new [ ( list_of_arguments ) ]
1972
   //    | new expression
1973

1974
   BEGIN("class new");
16✔
1975

1976
   consume(tNEW);
8✔
1977

1978
   if (dt == NULL || vlog_kind(dt) != V_CLASS_DECL) {
8✔
1979
      error_at(&state.last_loc, "new class expression must have class type");
1✔
1980
      dt = NULL;
1✔
1981
   }
1982

1983
   vlog_node_t v = vlog_new(V_CLASS_NEW);
8✔
1984
   vlog_set_type(v, dt);
8✔
1985

1986
   if (optional(tLPAREN)) {
8✔
1987
      p_list_of_arguments(v);
2✔
1988
      consume(tRPAREN);
2✔
1989
   }
1990

1991
   vlog_set_loc(v, CURRENT_LOC);
8✔
1992
   return v;
8✔
1993
}
1994

1995
static vlog_assign_t p_assignment_operator(void)
175✔
1996
{
1997
   // = | += | -= | *= | /= | %= | &= | |= | ^= | <<= | >>= | <<<= | >>>=
1998

1999
   BEGIN("assignment operator");
350✔
2000

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

2019
static vlog_node_t p_operator_assignment(vlog_node_t lhs)
175✔
2020
{
2021
   // variable_lvalue assignment_operator expression
2022

2023
   BEGIN_WITH_HEAD("operator assignment", lhs);
350✔
2024

2025
   vlog_node_t v = vlog_new(V_OP_ASSIGN);
175✔
2026
   vlog_set_subkind(v, p_assignment_operator());
175✔
2027
   vlog_set_target(v, lhs);
175✔
2028

2029
   vlog_set_value(v, p_expression());
175✔
2030

2031
   vlog_set_loc(v, CURRENT_LOC);
175✔
2032
   return v;
175✔
2033
}
2034

2035
static vlog_node_t p_blocking_assignment(vlog_node_t lhs)
10,404✔
2036
{
2037
   // variable_lvalue = delay_or_event_control expression
2038
   //   | nonrange_variable_lvalue = dynamic_array_new
2039
   //   | [ implicit_class_handle . | class_scope | package_scope ]
2040
   //         hierarchical_variable_identifier select = class_new
2041
   //   | operator_assignment
2042

2043
   BEGIN_WITH_HEAD("blocking assignment", lhs);
20,808✔
2044

2045
   switch (peek()) {
10,404✔
2046
   case tPLUSEQ:
107✔
2047
   case tMINUSEQ:
2048
   case tTIMESEQ:
2049
   case tDIVEQ:
2050
   case tPERCENTEQ:
2051
   case tAMPEQ:
2052
   case tBAREQ:
2053
   case tCARETEQ:
2054
   case tLSLEQ:
2055
   case tLSREQ:
2056
   case tASLEQ:
2057
   case tASREQ:
2058
      return p_operator_assignment(lhs);
107✔
2059
   }
2060

2061
   consume(tEQ);
10,297✔
2062

2063
   vlog_node_t v = vlog_new(V_BASSIGN);
10,297✔
2064
   vlog_set_target(v, lhs);
10,297✔
2065

2066
   if (peek() == tNEW)
10,297✔
2067
      vlog_set_value(v, p_class_new(vlog_get_type(lhs)));
8✔
2068
   else {
2069
      if (scan(tHASH, tAT))
10,289✔
2070
         vlog_set_delay(v, p_delay_or_event_control());
33✔
2071

2072
      vlog_set_value(v, p_expression());
10,289✔
2073
   }
2074

2075
   vlog_set_loc(v, CURRENT_LOC);
10,297✔
2076
   return v;
10,297✔
2077
}
2078

2079
static vlog_node_t p_nonblocking_assignment(vlog_node_t lhs)
324✔
2080
{
2081
   // variable_lvalue <= [ delay_or_event_control ] expression
2082

2083
   BEGIN_WITH_HEAD("non-blocking assignment", lhs);
648✔
2084

2085
   consume(tLE);
324✔
2086

2087
   vlog_node_t v = vlog_new(V_NBASSIGN);
324✔
2088
   vlog_set_target(v, lhs);
324✔
2089

2090
   if (scan(tHASH, tAT))
324✔
2091
      vlog_set_delay(v, p_delay_or_event_control());
17✔
2092

2093
   vlog_set_value(v, p_expression());
324✔
2094

2095
   vlog_set_loc(v, CURRENT_LOC);
324✔
2096
   return v;
324✔
2097
}
2098

2099
static vlog_node_t p_procedural_timing_control(void)
4,868✔
2100
{
2101
   // delay_control | event_control | cycle_delay
2102

2103
   BEGIN("procedural timing control");
9,736✔
2104

2105
   switch (peek()) {
4,868✔
2106
   case tAT:
339✔
2107
      return p_event_control();
339✔
2108
   case tHASH:
4,529✔
2109
      return p_delay_control();
4,529✔
UNCOV
2110
   default:
×
2111
      should_not_reach_here();
2112
   }
2113
}
2114

2115
static vlog_node_t p_procedural_timing_control_statement(void)
4,868✔
2116
{
2117
   // procedural_timing_control statement_or_null
2118

2119
   BEGIN("procedural timing control statement");
9,736✔
2120

2121
   vlog_node_t v = vlog_new(V_TIMING);
4,868✔
2122
   vlog_set_value(v, p_procedural_timing_control());
4,868✔
2123

2124
   vlog_node_t s = p_statement_or_null();
4,868✔
2125
   if (s != NULL)
4,868✔
2126
      vlog_add_stmt(v, s);
572✔
2127

2128
   vlog_set_loc(v, CURRENT_LOC);
4,868✔
2129
   return v;
4,868✔
2130
}
2131

2132
static vlog_node_t p_seq_block(ident_t id)
2,543✔
2133
{
2134
   // begin [ : block_identifier ] { block_item_declaration }
2135
   //   { statement_or_null } end [ : block_identifier ]
2136

2137
   BEGIN("sequential block");
5,086✔
2138

2139
   consume(tBEGIN);
2,543✔
2140

2141
   vlog_node_t v = vlog_new(V_BLOCK);
2,543✔
2142
   vlog_set_ident(v, id);
2,543✔
2143
   vlog_set_loc(v, CURRENT_LOC);
2,543✔
2144

2145
   vlog_symtab_push(symtab, v);
2,543✔
2146

2147
   if (optional(tCOLON)) {
2,543✔
2148
      ident_t name = p_identifier();
14✔
2149
      if (vlog_has_ident(v))
14✔
2150
         parse_error(&state.last_loc, "cannot specify both a statement label "
1✔
2151
                     "and a block name");
2152
      else
2153
         vlog_set_ident(v, name);
13✔
2154
   }
2155

2156
   skip_over_attributes();
2,543✔
2157

2158
   while (scan_block_item_declaration()) {
2,559✔
2159
      p_block_item_declaration(v);
16✔
2160
      skip_over_attributes();
16✔
2161
   }
2162

2163
   while (not_at_token(tEND)) {
25,046✔
2164
      vlog_node_t s = p_statement_or_null();
22,503✔
2165
      if (s != NULL)
22,503✔
2166
         vlog_add_stmt(v, s);
22,502✔
2167
   }
2168

2169
   vlog_symtab_pop(symtab);
2,543✔
2170

2171
   consume(tEND);
2,543✔
2172

2173
   if (optional(tCOLON)) {
2,543✔
2174
      ident_t name = p_identifier();
6✔
2175
      if (!vlog_has_ident(v))
6✔
2176
         parse_error(&state.last_loc, "initial block does not have a label");
1✔
2177
      else if (name != vlog_ident(v))
5✔
2178
         parse_error(&state.last_loc, "'%s' does not match label '%s'",
1✔
2179
                     istr(name), istr(vlog_ident(v)));
2180
   }
2181

2182
   return v;
2,543✔
2183
}
2184

2185
static vlog_node_t p_par_block(ident_t id)
7✔
2186
{
2187
   // fork [ : block_identifier ] { block_item_declaration }
2188
   //   { statement_or_null } join_keyword [ : block_identifier ]
2189

2190
   BEGIN("parallel block");
14✔
2191

2192
   consume(tFORK);
7✔
2193

2194
   vlog_node_t v = vlog_new(V_FORK);
7✔
2195
   vlog_set_ident(v, id);
7✔
2196
   vlog_set_loc(v, CURRENT_LOC);
7✔
2197

2198
   vlog_symtab_push(symtab, v);
7✔
2199

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

2209
   skip_over_attributes();
7✔
2210

2211
   while (scan_block_item_declaration()) {
9✔
2212
      p_block_item_declaration(v);
2✔
2213
      skip_over_attributes();
2✔
2214
   }
2215

2216
   while (not_at_token(tJOIN)) {
14✔
2217
      vlog_node_t s = p_statement_or_null();
7✔
2218
      if (s != NULL)
7✔
2219
         vlog_add_stmt(v, s);
7✔
2220
   }
2221

2222
   vlog_symtab_pop(symtab);
7✔
2223

2224
   consume(tJOIN);
7✔
2225

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

2235
   return v;
7✔
2236
}
2237

2238
static vlog_node_t p_subroutine_call_statement(void)
6,599✔
2239
{
2240
   // subroutine_call ; | void ' ( function_subroutine_call ) ;
2241

2242
   BEGIN("subroutine call statement");
13,198✔
2243

2244
   vlog_node_t v;
6,599✔
2245
   switch (peek()) {
6,599✔
2246
   case tSYSTASK:
6,470✔
2247
      v = p_subroutine_call(V_SYS_TCALL);
6,470✔
2248
      break;
6,470✔
2249
   case tVOID:
2✔
2250
      {
2251
         consume(tVOID);
2✔
2252
         consume(tTICK);
2✔
2253
         consume(tLPAREN);
2✔
2254

2255
         const vlog_kind_t kind =
4✔
2256
            peek() == tSYSTASK ? V_SYS_FCALL : V_USER_FCALL;
2✔
2257

2258
         v = vlog_new(V_VOID_CALL);
2✔
2259
         vlog_set_value(v, p_subroutine_call(kind));
2✔
2260

2261
         consume(tRPAREN);
2✔
2262
      }
2263
      break;
2✔
2264
   case tID:
127✔
2265
   default:
2266
      v = p_subroutine_call(V_USER_TCALL);
127✔
2267
      break;
127✔
2268
   }
2269

2270
   consume(tSEMI);
6,599✔
2271

2272
   vlog_set_loc(v, CURRENT_LOC);
6,599✔
2273
   return v;
6,599✔
2274
}
2275

2276
static vlog_node_t p_conditional_statement(void)
2,272✔
2277
{
2278
   // [ unique_priority ] if ( cond_predicate ) statement_or_null
2279
   //     { else if ( cond_predicate ) statement_or_null }
2280
   //     [ else statement_or_null ]
2281

2282
   BEGIN("conditional statement");
4,544✔
2283

2284
   vlog_node_t v = vlog_new(V_IF);
2,272✔
2285

2286
   consume(tIF);
2,272✔
2287
   consume(tLPAREN);
2,272✔
2288

2289
   vlog_node_t c0 = vlog_new(V_COND);
2,272✔
2290
   vlog_set_value(c0, p_cond_predicate());
2,272✔
2291
   vlog_add_cond(v, c0);
2,272✔
2292

2293
   consume(tRPAREN);
2,272✔
2294

2295
   vlog_node_t s0 = p_statement_or_null();
2,272✔
2296
   if (s0 != NULL)
2,272✔
2297
      vlog_add_stmt(c0, s0);
2,261✔
2298

2299
   bool stop = false;
2300
   while (!stop && optional(tELSE)) {
2,659✔
2301
      vlog_node_t c = vlog_new(V_COND);
387✔
2302
      vlog_add_cond(v, c);
387✔
2303

2304
      if (optional(tIF)) {
387✔
2305
         consume(tLPAREN);
37✔
2306
         vlog_set_value(c, p_cond_predicate());
37✔
2307
         consume(tRPAREN);
37✔
2308
      }
2309
      else
2310
         stop = true;
2311

2312
      vlog_node_t s = p_statement_or_null();
387✔
2313
      if (s != NULL)
387✔
2314
         vlog_add_stmt(c, s);
386✔
2315
   }
2316

2317
   vlog_set_loc(v, CURRENT_LOC);
2,272✔
2318
   return v;
2,272✔
2319
}
2320

2321
static vlog_node_t p_variable_assignment(vlog_kind_t kind)
86✔
2322
{
2323
   // variable_lvalue = expression
2324

2325
   BEGIN("variable assignment");
172✔
2326

2327
   vlog_node_t v = vlog_new(kind);
86✔
2328
   vlog_set_target(v, p_variable_lvalue());
86✔
2329

2330
   consume(tEQ);
86✔
2331

2332
   vlog_set_value(v, p_expression());
86✔
2333

2334
   vlog_set_loc(v, CURRENT_LOC);
86✔
2335
   return v;
86✔
2336
}
2337

2338
static void p_list_of_variable_assignments(vlog_node_t parent)
84✔
2339
{
2340
   // variable_assignment { , variable_assignment }
2341

2342
   BEGIN("list of variable assignments");
168✔
2343

2344
   do {
84✔
2345
      vlog_node_t v = p_variable_assignment(V_BASSIGN);
84✔
2346
      vlog_add_stmt(parent, v);
84✔
2347
   } while (optional(tCOMMA));
84✔
2348
}
84✔
2349

2350
static void p_for_variable_declaration(vlog_node_t parent)
7✔
2351
{
2352
   // [ var ] data_type variable_identifier = expression
2353
   //   { , variable_identifier = expression }
2354

2355
   BEGIN("for variable declaration");
14✔
2356

2357
   optional(tVAR);
7✔
2358

2359
   vlog_node_t dt = p_data_type();
7✔
2360

2361
   do {
7✔
2362
      vlog_node_t v = vlog_new(V_VAR_DECL);
7✔
2363
      vlog_set_ident(v, p_identifier());
7✔
2364
      vlog_set_type(v, dt);
7✔
2365

2366
      consume(tEQ);
7✔
2367

2368
      vlog_set_value(v, p_expression());
7✔
2369

2370
      vlog_set_loc(v, CURRENT_LOC);
7✔
2371
      vlog_add_decl(parent, v);
7✔
2372

2373
      vlog_symtab_put(symtab, v);
7✔
2374
   } while (optional(tCOMMA));
7✔
2375
}
7✔
2376

2377
static vlog_node_t p_for_initialization(void)
91✔
2378
{
2379
   // list_of_variable_assignments
2380
   //   | for_variable_declaration { , for_variable_declaration }
2381

2382
   BEGIN("for initialization");
182✔
2383

2384
   vlog_node_t v = vlog_new(V_FOR_INIT);
91✔
2385

2386
   if (scan(tREG, tSTRUCT, tUNION, tENUM, tSVINT, tINTEGER, tSVREAL,
91✔
2387
            tSHORTREAL, tREALTIME, tLOGIC, tVAR)) {
2388
      do {
7✔
2389
         p_for_variable_declaration(v);
7✔
2390
      } while (optional(tCOMMA));
7✔
2391
   }
2392
   else
2393
      p_list_of_variable_assignments(v);
84✔
2394

2395
   vlog_set_loc(v, CURRENT_LOC);
91✔
2396
   return v;
91✔
2397
}
2398

2399
static vlog_node_t p_for_step(void)
91✔
2400
{
2401
   // operator_assignment | inc_or_dec_expression | function_subroutine_call
2402

2403
   BEGIN("for step");
182✔
2404

2405
   vlog_node_t v = vlog_new(V_FOR_STEP);
91✔
2406

2407
   switch (peek()) {
91✔
2408
   case tPLUSPLUS:
1✔
2409
   case tMINUSMINUS:
2410
      vlog_add_stmt(v, p_inc_or_dec_expression(NULL));
1✔
2411
      break;
1✔
2412
   default:
90✔
2413
      {
2414
         vlog_node_t head = p_variable_lvalue();
90✔
2415

2416
         switch (peek()) {
90✔
2417
         case tPLUSPLUS:
22✔
2418
         case tMINUSMINUS:
2419
            vlog_add_stmt(v, p_inc_or_dec_expression(head));
22✔
2420
            break;
22✔
2421
         default:
68✔
2422
            vlog_add_stmt(v, p_operator_assignment(head));
68✔
2423
            break;
68✔
2424
         }
2425
      }
2426
      break;
2427
   }
2428

2429
   vlog_set_loc(v, CURRENT_LOC);
91✔
2430
   return v;
91✔
2431
}
2432

2433
static vlog_node_t p_loop_statement(void)
131✔
2434
{
2435
   // forever statement_or_null
2436
   //   | repeat ( expression ) statement_or_null
2437
   //   | while ( expression ) statement_or_null
2438
   //   | for ( [ for_initialization ] ; [ expression ] ; [ for_step ] )
2439
   //       statement_or_null
2440
   //   | do statement_or_null while ( expression ) ;
2441
   //   | foreach ( ps_or_hierarchical_array_identifier [ loop_variables ] )
2442
   //       statement
2443

2444
   BEGIN("loop statement");
262✔
2445

2446
   switch (one_of(tFOREVER, tWHILE, tREPEAT, tDO, tFOR)) {
131✔
2447
   case tFOREVER:
13✔
2448
      {
2449
         vlog_node_t v = vlog_new(V_FOREVER);
13✔
2450

2451
         vlog_node_t s = p_statement_or_null();
13✔
2452
         if (s != NULL)
13✔
2453
            vlog_add_stmt(v, s);
13✔
2454

2455
         vlog_set_loc(v, CURRENT_LOC);
13✔
2456
         return v;
13✔
2457
      }
2458

2459
   case tWHILE:
6✔
2460
      {
2461
         vlog_node_t v = vlog_new(V_WHILE);
6✔
2462

2463
         consume(tLPAREN);
6✔
2464
         vlog_set_value(v, p_expression());
6✔
2465
         consume(tRPAREN);
6✔
2466

2467
         vlog_node_t s = p_statement_or_null();
6✔
2468
         if (s != NULL)
6✔
2469
            vlog_add_stmt(v, s);
4✔
2470

2471
         vlog_set_loc(v, CURRENT_LOC);
6✔
2472
         return v;
6✔
2473
      }
2474

2475
   case tREPEAT:
18✔
2476
      {
2477
         vlog_node_t v = vlog_new(V_REPEAT);
18✔
2478

2479
         consume(tLPAREN);
18✔
2480
         vlog_set_value(v, p_expression());
18✔
2481
         consume(tRPAREN);
18✔
2482

2483
         vlog_node_t s = p_statement_or_null();
18✔
2484
         if (s != NULL)
18✔
2485
            vlog_add_stmt(v, s);
18✔
2486

2487
         vlog_set_loc(v, CURRENT_LOC);
18✔
2488
         return v;
18✔
2489
      }
2490

2491
   case tDO:
2✔
2492
      {
2493
         vlog_node_t v = vlog_new(V_DO_WHILE);
2✔
2494

2495
         vlog_node_t s = p_statement_or_null();
2✔
2496
         if (s != NULL)
2✔
2497
            vlog_add_stmt(v, s);
2✔
2498

2499
         consume(tWHILE);
2✔
2500

2501
         consume(tLPAREN);
2✔
2502
         vlog_set_value(v, p_expression());
2✔
2503
         consume(tRPAREN);
2✔
2504
         consume(tSEMI);
2✔
2505

2506
         vlog_set_loc(v, CURRENT_LOC);
2✔
2507
         return v;
2✔
2508
      }
2509

2510
   case tFOR:
92✔
2511
      {
2512
         vlog_node_t v = vlog_new(V_FOR_LOOP);
92✔
2513

2514
         vlog_symtab_push(symtab, v);
92✔
2515

2516
         consume(tLPAREN);
92✔
2517

2518
         if (not_at_token(tSEMI))
92✔
2519
            vlog_set_left(v, p_for_initialization());
91✔
2520
         else
2521
            vlog_set_left(v, vlog_new(V_FOR_INIT));
1✔
2522

2523
         consume(tSEMI);
92✔
2524

2525
         if (not_at_token(tSEMI))
92✔
2526
            vlog_set_value(v, p_expression());
90✔
2527

2528
         consume(tSEMI);
92✔
2529

2530
         if (not_at_token(tRPAREN))
92✔
2531
            vlog_set_right(v, p_for_step());
91✔
2532
         else
2533
            vlog_set_right(v, vlog_new(V_FOR_STEP));
1✔
2534

2535
         consume(tRPAREN);
92✔
2536

2537
         vlog_node_t s = p_statement_or_null();
92✔
2538
         if (s != NULL)
92✔
2539
            vlog_add_stmt(v, s);
89✔
2540

2541
         vlog_symtab_pop(symtab);
92✔
2542

2543
         vlog_set_loc(v, CURRENT_LOC);
92✔
2544
         return v;
92✔
2545
      }
2546

UNCOV
2547
   default:
×
2548
      should_not_reach_here();
2549
   }
2550
}
2551

2552
static vlog_node_t p_wait_statement(void)
1✔
2553
{
2554
   // wait ( expression ) statement_or_null
2555
   //   | wait fork ;
2556
   //   | wait_order ( hierarchical_identifier { , hierarchical_identifier } )
2557
   //       action_block
2558

2559
   BEGIN("wait statement");
2✔
2560

2561
   consume(tWAIT);
1✔
2562

2563
   vlog_node_t v = vlog_new(V_WAIT);
1✔
2564

2565
   consume(tLPAREN);
1✔
2566

2567
   vlog_set_value(v, p_expression());
1✔
2568

2569
   consume(tRPAREN);
1✔
2570

2571
   vlog_node_t s = p_statement_or_null();
1✔
2572
   if (s != NULL)
1✔
2573
      vlog_add_stmt(v, s);
1✔
2574

2575
   vlog_set_loc(v, CURRENT_LOC);
1✔
2576
   return v;
1✔
2577
}
2578

2579
static vlog_node_t p_case_item(void)
196✔
2580
{
2581
   // case_item_expression { , case_item_expression } : statement_or_null
2582
   //   | default [ : ] statement_or_null
2583

2584
   BEGIN("case item");
392✔
2585

2586
   vlog_node_t v = vlog_new(V_CASE_ITEM);
196✔
2587

2588
   if (optional(tDEFAULT))
196✔
2589
      optional(tCOLON);
43✔
2590
   else {
2591
      do {
157✔
2592
         vlog_add_param(v, p_expression());
157✔
2593
      } while (optional(tCOMMA));
157✔
2594

2595
      consume(tCOLON);
153✔
2596
   }
2597

2598
   vlog_set_loc(v, CURRENT_LOC);
196✔
2599

2600
   vlog_node_t s = p_statement_or_null();
196✔
2601
   if (s != NULL)
196✔
2602
      vlog_add_stmt(v, s);
195✔
2603

2604
   return v;
196✔
2605
}
2606

2607
static vlog_node_t p_case_statement(void)
54✔
2608
{
2609
   // [ unique_priority ] case_keyword ( case_expression )
2610
   //        case_item { case_item } endcase
2611
   //   | [ unique_priority ] case_keyword ( case_expression ) matches
2612
   //        case_pattern_item { case_pattern_item } endcase
2613
   //   | [ unique_priority ] case ( case_expression ) inside case_inside_item
2614
   //        { case_inside_item } endcase
2615

2616
   BEGIN("case statement");
108✔
2617

2618
   vlog_case_kind_t kind = V_CASE_NORMAL;
54✔
2619
   switch (one_of(tCASE, tCASEX, tCASEZ)) {
54✔
2620
   case tCASEX: kind = V_CASE_X; break;
9✔
2621
   case tCASEZ: kind = V_CASE_Z; break;
12✔
2622
   }
2623

2624
   vlog_node_t v = vlog_new(V_CASE);
54✔
2625
   vlog_set_subkind(v, kind);
54✔
2626

2627
   consume(tLPAREN);
54✔
2628

2629
   vlog_set_value(v, p_expression());
54✔
2630

2631
   consume(tRPAREN);
54✔
2632

2633
   do {
196✔
2634
      vlog_add_stmt(v, p_case_item());
196✔
2635
   } while (not_at_token(tENDCASE));
196✔
2636

2637
   consume(tENDCASE);
54✔
2638

2639
   vlog_set_loc(v, CURRENT_LOC);
54✔
2640
   return v;
54✔
2641
}
2642

2643
static vlog_node_t p_event_trigger(void)
1✔
2644
{
2645
   // -> hierarchical_event_identifier ;
2646
   //   | ->> [ delay_or_event_control ] hierarchical_event_identifier ;
2647

2648
   BEGIN("event trigger");
2✔
2649

2650
   consume(tIFIMPL);
1✔
2651

2652
   vlog_node_t v = vlog_new(V_EVENT_TRIGGER);
1✔
2653
   vlog_set_ident(v, p_identifier());
1✔
2654

2655
   consume(tSEMI);
1✔
2656

2657
   vlog_set_loc(v, CURRENT_LOC);
1✔
2658
   return v;
1✔
2659
}
2660

2661
static vlog_node_t p_procedural_continuous_assignment(void)
4✔
2662
{
2663
   // assign variable_assignment | deassign variable_lvalue
2664
   //   | force variable_assignment | force net_assignment
2665
   //   | release variable_lvalue | release net_lvalue
2666

2667
   BEGIN("procedural continuous assignment");
8✔
2668

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

2692
static vlog_node_t p_disable_statement(void)
1✔
2693
{
2694
   // disable hierarchical_task_identifier ;
2695
   //   | disable hierarchical_block_identifier ;
2696
   //   | disable fork ;
2697

2698
   BEGIN("disable statement");
2✔
2699

2700
   consume(tDISABLE);
1✔
2701

2702
   vlog_node_t v = vlog_new(V_DISABLE);
1✔
2703
   vlog_set_ident(v, p_identifier());
1✔
2704

2705
   consume(tSEMI);
1✔
2706

2707
   vlog_set_loc(v, CURRENT_LOC);
1✔
2708
   return v;
1✔
2709
}
2710

2711
static vlog_node_t p_jump_statement(void)
7✔
2712
{
2713
   // return [ expression ] ; | break ; | continue ;
2714

2715
   BEGIN("jump statement");
14✔
2716

2717
   switch (one_of(tRETURN)) {
7✔
2718
   case tRETURN:
7✔
2719
      {
2720
         vlog_node_t v = vlog_new(V_RETURN);
7✔
2721

2722
         vlog_node_t subr = vlog_symtab_subr(symtab);
7✔
2723
         if (subr == NULL)
7✔
2724
            parse_error(&state.last_loc, "return statement can only be used "
1✔
2725
                        "in a subroutine");
2726
         else
2727
            vlog_set_ref(v, subr);
6✔
2728

2729
         if (peek() != tSEMI)
7✔
2730
            vlog_set_value(v, p_expression());
5✔
2731

2732
         consume(tSEMI);
7✔
2733

2734
         vlog_set_loc(v, CURRENT_LOC);
7✔
2735
         return v;
14✔
2736
      }
UNCOV
2737
   default:
×
2738
      should_not_reach_here();
2739
   }
2740
}
2741

2742
static vlog_node_t p_statement_item(ident_t id)
27,230✔
2743
{
2744
   // blocking_assignment ; | nonblocking_assignment ;
2745
   //   | procedural_continuous_assignment ; | case_statement
2746
   //   | conditional_statement | inc_or_dec_expression ;
2747
   //   | subroutine_call_statement | disable_statement
2748
   //   | event_trigger | loop_statement | jump_statement
2749
   //   | par_block | procedural_timing_control_statement
2750
   //   | seq_block | wait_statement | procedural_assertion_statement
2751
   //   | clocking_drive ; | randsequence_statement | randcase_statement
2752
   //   | expect_property_statement
2753

2754
   BEGIN("statement item");
54,460✔
2755

2756
   switch (peek()) {
27,230✔
2757
   case tID:
10,862✔
2758
      switch (peek_nth(2)) {
10,862✔
2759
      case tLPAREN:
127✔
2760
      case tSEMI:
2761
      case tATTRBEGIN:
2762
         return p_subroutine_call_statement();
127✔
2763
      default:
10,735✔
2764
         {
2765
            vlog_node_t lhs = p_variable_lvalue(), v;
10,735✔
2766

2767
            switch (peek()) {
10,735✔
2768
            case tLE:
324✔
2769
               v = p_nonblocking_assignment(lhs);
324✔
2770
               break;
324✔
2771
            case tPLUSPLUS:
12✔
2772
            case tMINUSMINUS:
2773
               v = p_inc_or_dec_expression(lhs);
12✔
2774
               break;
12✔
2775
            default:
10,399✔
2776
               v = p_blocking_assignment(lhs);
10,399✔
2777
               break;
10,399✔
2778
            }
2779

2780
            consume(tSEMI);
10,735✔
2781
            return v;
10,735✔
2782
         }
2783
      }
2784
   case tLBRACE:
5✔
2785
      {
2786
         vlog_node_t lhs = p_variable_lvalue(), v;
5✔
2787

2788
         if (peek() == tLE)
5✔
UNCOV
2789
            v = p_nonblocking_assignment(lhs);
×
2790
         else
2791
            v = p_blocking_assignment(lhs);
5✔
2792

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

2844
static vlog_node_t p_statement(void)
27,230✔
2845
{
2846
   // [ block_identifier : ] { attribute_instance } statement_item
2847

2848
   BEGIN("statement");
54,460✔
2849

2850
   ident_t id = NULL;
27,230✔
2851
   if (peek() == tID && peek_nth(2) == tCOLON) {
27,230✔
2852
      id = p_identifier();
6✔
2853
      consume(tCOLON);
6✔
2854
   }
2855

2856
   optional_attributes();
27,230✔
2857

2858
   return p_statement_item(id);
27,230✔
2859
}
2860

2861
static vlog_node_t p_statement_or_null(void)
31,236✔
2862
{
2863
   // statement | { attribute_instance } ;
2864

2865
   BEGIN("statement or null");
62,472✔
2866

2867
   if (optional(tSEMI))
31,236✔
2868
      return NULL;
2869
   else
2870
      return p_statement();
26,920✔
2871
}
2872

2873
static vlog_node_t p_always_construct(void)
310✔
2874
{
2875
   // always_keyword statement
2876

2877
   BEGIN("always construct");
620✔
2878

2879
   vlog_node_t v = vlog_new(V_ALWAYS);
310✔
2880

2881
   switch (one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH)) {
310✔
2882
   case tALWAYSCOMB:  vlog_set_subkind(v, V_ALWAYS_COMB);  break;
1✔
2883
   case tALWAYSFF:    vlog_set_subkind(v, V_ALWAYS_FF);    break;
1✔
2884
   case tALWAYSLATCH: vlog_set_subkind(v, V_ALWAYS_LATCH); break;
5✔
2885
   default:           vlog_set_subkind(v, V_ALWAYS_PLAIN); break;
303✔
2886
   }
2887

2888
   vlog_set_ident(v, default_label("always"));
310✔
2889
   vlog_add_stmt(v, p_statement());
310✔
2890

2891
   vlog_set_loc(v, CURRENT_LOC);
310✔
2892
   return v;
310✔
2893
}
2894

2895
static vlog_node_t p_initial_construct(void)
755✔
2896
{
2897
   // initial statement_or_null
2898

2899
   BEGIN("initial construct");
1,510✔
2900

2901
   consume(tINITIAL);
755✔
2902

2903
   vlog_node_t v = vlog_new(V_INITIAL);
755✔
2904
   vlog_set_ident(v, default_label("initial"));
755✔
2905

2906
   vlog_node_t s = p_statement_or_null();
755✔
2907
   if (s != NULL)
755✔
2908
      vlog_add_stmt(v, s);
755✔
2909

2910
   vlog_set_loc(v, CURRENT_LOC);
755✔
2911
   return v;
755✔
2912
}
2913

2914
static vlog_node_t p_net_assignment(vlog_node_t delay, vlog_node_t strength)
656✔
2915
{
2916
   // net_lvalue = expression
2917

2918
   BEGIN("net assignment");
1,312✔
2919

2920
   vlog_symtab_set_implicit(symtab, implicit_kind);
656✔
2921

2922
   vlog_node_t v = vlog_new(V_ASSIGN);
656✔
2923
   vlog_set_target(v, p_net_lvalue());
656✔
2924
   vlog_set_ident(v, default_label("assign"));
656✔
2925
   vlog_set_delay(v, delay);
656✔
2926
   if (strength != NULL)
656✔
2927
      vlog_add_param(v, strength);
51✔
2928

2929
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
656✔
2930

2931
   consume(tEQ);
656✔
2932

2933
   vlog_set_value(v, p_expression());
656✔
2934

2935
   vlog_set_loc(v, CURRENT_LOC);
656✔
2936
   return v;
656✔
2937
}
2938

2939
static void p_list_of_net_assignments(vlog_node_t mod, vlog_node_t delay,
656✔
2940
                                      vlog_node_t strength)
2941
{
2942
   // net_assignment { , net_assignment }
2943

2944
   BEGIN("list of net assignments");
1,312✔
2945

2946
   do {
656✔
2947
      vlog_add_stmt(mod, p_net_assignment(delay, strength));
656✔
2948
   } while (optional(tCOMMA));
656✔
2949
}
656✔
2950

2951
static void p_continuous_assign(vlog_node_t mod)
656✔
2952
{
2953
   // assign [ drive_strength ] [ delay3 ] list_of_net_assignments ;
2954
   //   | assign [ delay_control ] list_of_variable_assignments ;
2955

2956
   BEGIN("continuous assignment");
1,312✔
2957

2958
   consume(tASSIGN);
656✔
2959

2960
   vlog_node_t delay = NULL;
656✔
2961
   vlog_node_t strength = NULL;
656✔
2962
   if (peek() == tLPAREN) {
656✔
2963
      strength = p_drive_strength();
51✔
2964
      if (peek() == tHASH)
51✔
2965
         p_delay3();
2✔
2966
   } else if (peek() == tHASH)
605✔
2967
      delay = p_delay_control();
12✔
2968

2969
   p_list_of_net_assignments(mod, delay, strength);
656✔
2970

2971
   consume(tSEMI);
656✔
2972
}
656✔
2973

2974
static vlog_net_kind_t p_net_type(void)
987✔
2975
{
2976
   // supply0 | supply1 | tri | triand | trior | trireg | tri0
2977
   //   | tri1 | uwire | wire | wand | wor
2978

2979
   BEGIN("net type");
1,974✔
2980

2981
   switch (one_of(tWIRE, tUWIRE, tSUPPLY0, tSUPPLY1, tTRI, tTRIAND,
987✔
2982
                  tTRIOR, tTRIREG, tTRI0, tTRI1, tWAND, tWOR)) {
2983
   case tSUPPLY0: return V_NET_SUPPLY0;
2984
   case tSUPPLY1: return V_NET_SUPPLY1;
4✔
2985
   case tTRI:     return V_NET_TRI;
1✔
2986
   case tTRIAND:  return V_NET_TRIAND;
2✔
2987
   case tTRIOR:   return V_NET_TRIOR;
2✔
2988
   case tTRIREG:  return V_NET_TRIREG;
1✔
2989
   case tTRI0:    return V_NET_TRI0;
4✔
2990
   case tTRI1:    return V_NET_TRI1;
2✔
2991
   case tUWIRE:   return V_NET_UWIRE;
1✔
2992
   case tWAND:    return V_NET_WAND;
1✔
2993
   case tWOR:     return V_NET_WOR;
1✔
2994
   case tWIRE:
960✔
2995
   default:       return V_NET_WIRE;
960✔
2996
   }
2997
}
2998

2999
static vlog_node_t p_net_decl_assignment(vlog_net_kind_t kind,
994✔
3000
                                         vlog_node_t datatype)
3001
{
3002
   // net_identifier { unpacked_dimension } [ = expression ]
3003

3004
   BEGIN("net declaration assignment");
1,988✔
3005

3006
   vlog_node_t v = vlog_new(V_NET_DECL);
994✔
3007
   vlog_set_subkind(v, kind);
994✔
3008
   vlog_set_type(v, datatype);
994✔
3009
   vlog_set_ident(v, p_identifier());
994✔
3010

3011
   while (peek() == tLSQUARE)
1,008✔
3012
      vlog_add_range(v, p_unpacked_dimension());
14✔
3013

3014
   if (optional(tEQ))
994✔
3015
      vlog_set_value(v, p_expression());
393✔
3016

3017
   vlog_set_loc(v, CURRENT_LOC);
994✔
3018
   vlog_symtab_put(symtab, v);
994✔
3019
   return v;
994✔
3020
}
3021

3022
static void p_list_of_net_decl_assignments(vlog_node_t mod,
901✔
3023
                                           vlog_net_kind_t kind,
3024
                                           vlog_node_t datatype)
3025
{
3026
   // net_decl_assignment { , net_decl_assignment }
3027

3028
   BEGIN("list of net declaration assignments");
1,802✔
3029

3030
   do {
994✔
3031
      vlog_node_t v = p_net_decl_assignment(kind, datatype);
994✔
3032
      vlog_add_decl(mod, v);
994✔
3033
   } while (optional(tCOMMA));
994✔
3034
}
901✔
3035

3036
static vlog_node_t p_drive_strength(void)
55✔
3037
{
3038
   //( strength0 , strength1 ) | ( strength1 , strength0 )
3039
   //| ( strength0 , highz1 )  | ( strength1 , highz0 )
3040
   //| ( highz0 , strength1 )  | ( highz1 , strength0 )
3041

3042
   BEGIN("drive strength");
110✔
3043

3044
   consume(tLPAREN);
55✔
3045

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

3094
   consume(tRPAREN);
55✔
3095

3096
   vlog_node_t v = vlog_new(V_STRENGTH);
55✔
3097
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
55✔
3098
   vlog_set_loc(v, CURRENT_LOC);
55✔
3099

3100
   return v;
55✔
3101
}
3102

3103
static vlog_strength_t p_charge_strength(void)
2✔
3104
{
3105
   // ( small ) | ( medium ) | ( large )
3106

3107
   BEGIN("drive charge");
4✔
3108

3109
   consume(tLPAREN);
2✔
3110

3111
   vlog_strength_t s;
2✔
3112
   switch (one_of(tSMALL, tMEDIUM, tLARGE)) {
2✔
3113
   default:
3114
   case tSMALL:  s = V_STRENGTH_SMALL;
3115
   case tMEDIUM: s = V_STRENGTH_MEDIUM;
2✔
3116
   case tLARGE:  s = V_STRENGTH_LARGE;
2✔
3117
   }
3118

3119
   consume(tRPAREN);
2✔
3120

3121
   return s;
2✔
3122
}
3123

3124
static void p_net_declaration(vlog_node_t mod)
902✔
3125
{
3126
   // net_type [ drive_strength | charge_strength ] [ vectored | scalared ]
3127
   //     data_type_or_implicit [ delay3 ] list_of_net_decl_assignments ;
3128
   //  | net_type_identifier [ delay_control ] list_of_net_decl_assignments ;
3129
   //  | interconnect implicit_data_type [ # delay_value ] net_identifier
3130
   //     { unpacked_dimension } [ , net_identifier { unpacked_dimension } ] ;
3131

3132
   BEGIN("net declaration");
1,804✔
3133

3134
   ident_t id;
902✔
3135
   vlog_node_t dt;
902✔
3136
   vlog_net_kind_t kind = V_NET_WIRE;
902✔
3137

3138
   switch (peek()) {
902✔
3139
   case tINTERCONNECT:
1✔
3140
      {
3141
         consume(tINTERCONNECT);
1✔
3142

3143
         dt = p_implicit_data_type();
1✔
3144

3145
         if (optional(tHASH))
1✔
3146
            p_delay_value();
1✔
3147

3148
         do {
1✔
3149
            id = p_identifier();
1✔
3150
            if (peek() == tLSQUARE)
1✔
3151
               p_unpacked_dimension();
1✔
3152
         } while (optional(tCOMMA));
1✔
3153
      }
3154
      break;
3155

3156
   case tID:
×
3157
      {
3158
         id = p_identifier();
×
UNCOV
3159
         dt = vlog_symtab_query(symtab, id);
×
UNCOV
3160
         if (dt == NULL)
×
3161
            should_not_reach_here();
3162
         // TODO check that the identifier is actually
3163
         // a user declared nettype
3164

UNCOV
3165
         if (peek() == tHASH)
×
3166
            p_delay_control();
×
3167

3168
         p_list_of_net_decl_assignments(mod, kind, dt);
×
3169
      }
UNCOV
3170
      break;
×
3171

3172
   default:
901✔
3173
      {
3174
         kind = p_net_type();
901✔
3175

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

3206
         bool need_packed = false;
901✔
3207
         if (optional(tVECTORED) || optional(tSCALARED))
901✔
3208
            need_packed = true;
3209

3210
         dt = p_data_type_or_implicit();
901✔
3211

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

3225
         if (peek() == tHASH)
901✔
3226
            p_delay3();
5✔
3227

3228
         p_list_of_net_decl_assignments(mod, kind, dt);
901✔
3229
      }
3230
   }
3231

3232
   consume(tSEMI);
902✔
3233
}
3234

3235
static vlog_node_t p_unsized_dimension(void)
1✔
3236
{
3237
   // [ ]
3238

3239
   BEGIN("unsized dimension");
2✔
3240

3241
   consume(tLSQUARE);
1✔
3242
   consume(tRSQUARE);
1✔
3243

3244
   vlog_node_t v = vlog_new(V_DIMENSION);
1✔
3245
   vlog_set_subkind(v, V_DIM_UNSIZED);
1✔
3246
   vlog_set_loc(v, CURRENT_LOC);
1✔
3247

3248
   return v;
1✔
3249
}
3250

3251
static vlog_node_t p_variable_dimension(void)
71✔
3252
{
3253
   // unsized_dimension | unpacked_dimension | associative_dimension
3254
   //   | queue_dimension
3255

3256
   BEGIN("variable dimension");
142✔
3257

3258
   switch (peek_nth(2)) {
71✔
3259
   case tRSQUARE:
1✔
3260
      return p_unsized_dimension();
1✔
3261
   default:
70✔
3262
      return p_unpacked_dimension();
70✔
3263
   }
3264
}
3265

3266
static vlog_node_t p_variable_decl_assignment(vlog_node_t datatype)
4,172✔
3267
{
3268
   // variable_identifier { variable_dimension } [ = expression ]
3269
   //   | dynamic_array_variable_identifier unsized_dimension
3270
   //       { variable_dimension } [ = dynamic_array_new ]
3271
   //   | class_variable_identifier [ = class_new ]
3272

3273
   BEGIN("variable declaration assignment");
8,344✔
3274

3275
   vlog_node_t v = vlog_new(V_VAR_DECL);
4,172✔
3276
   vlog_set_ident(v, p_identifier());
4,172✔
3277
   vlog_set_type(v, datatype);
4,172✔
3278

3279
   while (peek() == tLSQUARE)
4,243✔
3280
      vlog_add_range(v, p_variable_dimension());
71✔
3281

3282
   if (optional(tEQ))
4,172✔
3283
      vlog_set_value(v, p_expression());
204✔
3284

3285
   vlog_set_loc(v, CURRENT_LOC);
4,172✔
3286
   vlog_symtab_put(symtab, v);
4,172✔
3287
   return v;
4,172✔
3288
}
3289

3290
static void p_list_of_variable_decl_assignments(vlog_node_t parent,
3,584✔
3291
                                                vlog_node_t datatype)
3292
{
3293
   // variable_decl_assignment { , variable_decl_assignment }
3294

3295
   BEGIN("list of variable declaration assignments");
7,168✔
3296

3297
   do {
4,172✔
3298
      vlog_add_decl(parent, p_variable_decl_assignment(datatype));
4,172✔
3299
   } while (optional(tCOMMA));
4,172✔
3300
}
3,584✔
3301

3302
static vlog_node_t p_type_declaration(void)
33✔
3303
{
3304
   // typedef data_type type_identifier { variable_dimension } ;
3305
   //   | typedef interface_instance_identifier constant_bit_select .
3306
   //       type_identifier type_identifier ;
3307
   //   | typedef [ enum | struct | union | class | interface class ]
3308
   //       type_identifier ;
3309

3310
   BEGIN("type declaration");
66✔
3311

3312
   consume(tTYPEDEF);
33✔
3313

3314
   vlog_node_t v = vlog_new(V_TYPE_DECL);
33✔
3315
   vlog_set_type(v, p_data_type());
33✔
3316
   vlog_set_ident(v, p_identifier());
33✔
3317

3318
   consume(tSEMI);
33✔
3319

3320
   vlog_set_loc(v, CURRENT_LOC);
33✔
3321
   vlog_symtab_put(symtab, v);
33✔
3322
   return v;
33✔
3323
}
3324

3325
static vlog_node_t p_package_import_item(void)
3✔
3326
{
3327
   // package_identifier :: identifier | package_identifier :: *
3328

3329
   BEGIN("package import item");
6✔
3330

3331
   vlog_node_t pack = p_package_identifier();
3✔
3332

3333
   vlog_node_t v = vlog_new(V_IMPORT_DECL);
3✔
3334
   vlog_set_ref(v, pack);
3✔
3335

3336
   consume(tSCOPE);
3✔
3337

3338
   if (peek() == tID)
3✔
3339
      vlog_set_ident(v, p_identifier());
1✔
3340
   else
3341
      one_of(tTIMES, tID);
2✔
3342

3343
   vlog_set_loc(v, CURRENT_LOC);
3✔
3344
   vlog_symtab_import(symtab, v);
3✔
3345
   return v;
3✔
3346
}
3347

3348
static void p_package_import_declaration(vlog_node_t parent)
3✔
3349
{
3350
   // import package_import_item { , package_import_item } ;
3351

3352
   BEGIN("package import declaration");
6✔
3353

3354
   consume(tIMPORT);
3✔
3355

3356
   do {
3✔
3357
      vlog_add_decl(parent, p_package_import_item());
3✔
3358
   } while (optional(tCOMMA));
3✔
3359

3360
   consume(tSEMI);
3✔
3361
}
3✔
3362

3363
static void p_data_declaration(vlog_node_t mod)
3,560✔
3364
{
3365
   // [ const ] [ var ] [ lifetime ] data_type_or_implicit
3366
   //     list_of_variable_decl_assignments ;
3367
   //  | type_declaration | package_import_declaration | net_type_declaration
3368

3369
   BEGIN("data declaration");
7,120✔
3370

3371
   switch (peek()) {
3,560✔
3372
   case tTYPEDEF:
33✔
3373
      vlog_add_decl(mod, p_type_declaration());
33✔
3374
      break;
33✔
3375
   case tIMPORT:
3✔
3376
      p_package_import_declaration(mod);
3✔
3377
      break;
3✔
3378
   default:
3,524✔
3379
      {
3380
         optional(tVAR);
3,524✔
3381

3382
         vlog_node_t dt = p_data_type_or_implicit();
3,524✔
3383
         p_list_of_variable_decl_assignments(mod, dt);
3,524✔
3384

3385
         consume(tSEMI);
3,524✔
3386
      }
3387
   }
3388
}
3,560✔
3389

3390
static v_port_kind_t p_port_direction(void)
106✔
3391
{
3392
   // input | output | inout | ref
3393

3394
   BEGIN("port direction");
212✔
3395

3396
   switch (one_of(tINPUT, tOUTPUT, tINOUT)) {
106✔
3397
   case tINPUT:  return V_PORT_INPUT;
3398
   case tOUTPUT: return V_PORT_OUTPUT;
4✔
3399
   case tINOUT:  return V_PORT_INOUT;
1✔
3400
   default:      return V_PORT_INPUT;
3401
   }
3402
}
3403

3404
static v_port_kind_t p_tf_port_direction(void)
106✔
3405
{
3406
   // port_direction | const ref
3407

3408
   BEGIN("task or function port direction");
212✔
3409

3410
   return p_port_direction();
106✔
3411
}
3412

3413
static vlog_node_t p_tf_port_item(void)
47✔
3414
{
3415
   // { attribute_instance } [ tf_port_direction ] [ var ]
3416
   //    data_type_or_implicit [ port_identifier { variable_dimension }
3417
   //    [ = expression ] ]
3418

3419
   BEGIN("task or function port item");
94✔
3420

3421
   vlog_node_t v = vlog_new(V_TF_PORT_DECL);
47✔
3422

3423
   skip_over_attributes();
47✔
3424

3425
   if (scan(tINPUT, tOUTPUT, tINOUT))
47✔
3426
      vlog_set_subkind(v, p_tf_port_direction());
36✔
3427
   else
3428
      vlog_set_subkind(v, V_PORT_INPUT);
11✔
3429

3430
   vlog_set_type(v, p_data_type_or_implicit());
47✔
3431

3432
   if (peek() == tID) {
47✔
3433
      vlog_set_ident(v, p_identifier());
46✔
3434

3435
      if (optional(tEQ))
46✔
3436
         vlog_set_value(v, p_expression());
2✔
3437
   }
3438

3439
   vlog_set_loc(v, CURRENT_LOC);
47✔
3440
   return v;
47✔
3441
}
3442

3443
static void p_tf_port_list(vlog_node_t tf)
35✔
3444
{
3445
   // tf_port_item { , tf_port_item }
3446

3447
   BEGIN("task or function port list");
70✔
3448

3449
   do {
45✔
3450
      vlog_node_t v = p_tf_port_item();
45✔
3451
      vlog_add_port(tf, v);
45✔
3452

3453
      if (vlog_has_ident(v))  // Ignore unnamed ports
45✔
3454
         vlog_symtab_put(symtab, v);
44✔
3455
   } while (optional(tCOMMA));
45✔
3456
}
35✔
3457

3458
static void p_list_of_tf_variable_identifiers(vlog_node_t tf,
70✔
3459
                                              v_port_kind_t kind,
3460
                                              vlog_node_t dt)
3461
{
3462
   // port_identifier { variable_dimension } [ = expression ]
3463
   //    { , port_identifier { variable_dimension } [ = expression ] }
3464

3465
   BEGIN("list of task or function variable identifiers");
140✔
3466

3467
   do {
80✔
3468
      vlog_node_t v = vlog_new(V_TF_PORT_DECL);
80✔
3469
      vlog_set_subkind(v, kind);
80✔
3470
      vlog_set_type(v, dt);
80✔
3471
      vlog_set_ident(v, p_identifier());
80✔
3472
      vlog_set_loc(v, &state.last_loc);
80✔
3473

3474
      if (optional(tEQ))
80✔
3475
         vlog_set_value(v, p_expression());
1✔
3476

3477
      vlog_add_port(tf, v);
80✔
3478
      vlog_symtab_put(symtab, v);
80✔
3479
   } while (optional(tCOMMA));
80✔
3480
}
70✔
3481

3482
static void p_tf_port_declaration(vlog_node_t tf)
70✔
3483
{
3484
   // { attribute_instance } tf_port_direction [ var ] data_type_or_implicit
3485
   //    list_of_tf_variable_identifiers ;
3486

3487
   BEGIN("task or function port declaration");
140✔
3488

3489
   v_port_kind_t kind = p_tf_port_direction();
70✔
3490

3491
   optional(tVAR);
70✔
3492

3493
   vlog_node_t dt = p_data_type_or_implicit();
70✔
3494

3495
   p_list_of_tf_variable_identifiers(tf, kind, dt);
70✔
3496

3497
   consume(tSEMI);
70✔
3498
}
70✔
3499

3500
static void p_tf_item_declaration(vlog_node_t tf)
92✔
3501
{
3502
   // block_item_declaration | tf_port_declaration
3503

3504
   BEGIN("task or function item declaration");
184✔
3505

3506
   switch (peek()) {
92✔
3507
   case tINPUT:
70✔
3508
   case tOUTPUT:
3509
   case tCONST:
3510
      p_tf_port_declaration(tf);
70✔
3511
      break;
70✔
3512
   default:
22✔
3513
      p_block_item_declaration(tf);
22✔
3514
      break;
22✔
3515
   }
3516
}
92✔
3517

3518
static void p_task_body_declaration(vlog_node_t task)
35✔
3519
{
3520
   // [ interface_identifier . | class_scope ] task_identifier ;
3521
   //    { tf_item_declaration } { statement_or_null }
3522
   //    endtask [ : task_identifier ]
3523
   // | [ interface_identifier . | class_scope ] task_identifier
3524
   //    ( [ tf_port_list ] ) ; { block_item_declaration }
3525
   //    { statement_or_null } endtask [ : task_identifier ]
3526

3527
   BEGIN("task body declaration");
70✔
3528

3529
   ident_t id = p_identifier();
35✔
3530
   vlog_set_ident(task, id);
35✔
3531
   vlog_set_loc(task, &state.last_loc);
35✔
3532

3533
   vlog_symtab_put(symtab, task);
35✔
3534

3535
   vlog_symtab_push(symtab, task);
35✔
3536

3537
   if (optional(tLPAREN)) {
35✔
3538
      if (peek() != tRPAREN)
7✔
3539
         p_tf_port_list(task);
7✔
3540
      consume(tRPAREN);
7✔
3541

3542
      consume(tSEMI);
7✔
3543

3544
      skip_over_attributes();
7✔
3545

3546
      while (scan_block_item_declaration()) {
7✔
UNCOV
3547
         p_block_item_declaration(task);
×
UNCOV
3548
         skip_over_attributes();
×
3549
      }
3550
   }
3551
   else {
3552
      consume(tSEMI);
28✔
3553

3554
      skip_over_attributes();
28✔
3555

3556
      while (scan_tf_item_declaration()) {
67✔
3557
         p_tf_item_declaration(task);
39✔
3558
         skip_over_attributes();
39✔
3559
      }
3560
   }
3561

3562
   while (not_at_token(tENDTASK)) {
70✔
3563
      vlog_node_t s = p_statement_or_null();
35✔
3564
      if (s != NULL)
35✔
3565
         vlog_add_stmt(task, s);
35✔
3566
   }
3567

3568
   consume(tENDTASK);
35✔
3569

3570
   if (optional(tCOLON)) {
35✔
3571
      ident_t name = p_identifier();
2✔
3572
      if (id != name)
2✔
3573
         error_at(&state.last_loc, "'%s' does not match task name '%s'",
1✔
3574
                  istr(name), istr(id));
3575
   }
3576

3577
   vlog_symtab_pop(symtab);
35✔
3578
}
35✔
3579

3580
static void p_lifetime(void)
1✔
3581
{
3582
   // static | automatic
3583

3584
   BEGIN("lifetime");
2✔
3585

3586
   one_of(tAUTOMATIC);
1✔
3587
}
1✔
3588

3589
static vlog_node_t p_task_declaration(void)
35✔
3590
{
3591
   // task [ dynamic_override_specifiers ] [ lifetime ] task_body_declaration
3592

3593
   BEGIN("task declaration");
70✔
3594

3595
   vlog_node_t v = vlog_new(V_TASK_DECL);
35✔
3596

3597
   consume(tTASK);
35✔
3598

3599
   if (scan(tAUTOMATIC))
35✔
UNCOV
3600
      p_lifetime();
×
3601

3602
   p_task_body_declaration(v);
35✔
3603

3604
   vlog_set_loc(v, CURRENT_LOC);
35✔
3605
   return v;
35✔
3606
}
3607

3608
static vlog_node_t p_function_data_type_or_implicit(void)
72✔
3609
{
3610
   // data_type_or_void | implicit_data_type
3611

3612
   BEGIN("function data type or implicit");
144✔
3613

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

3646
static void p_function_body_declaration(vlog_node_t func)
72✔
3647
{
3648
   // function_data_type_or_implicit [ interface_identifier . | class_scope ]
3649
   //    function_identifier ; { tf_item_declaration }
3650
   //    { function_statement_or_null } endfunction [ : function_identifier ]
3651
   // | function_data_type_or_implicit [ interface_identifier . | class_scope ]
3652
   //    function_identifier ( [ tf_port_list ] ) ; { block_item_declaration }
3653
   //    { function_statement_or_null } endfunction [ : function_identifier ]
3654

3655
   BEGIN("function body declaration");
144✔
3656

3657
   vlog_set_type(func, p_function_data_type_or_implicit());
72✔
3658

3659
   ident_t id = p_identifier();
72✔
3660
   vlog_set_ident(func, id);
72✔
3661
   vlog_set_loc(func, &state.last_loc);
72✔
3662

3663
   vlog_symtab_put(symtab, func);
72✔
3664

3665
   vlog_symtab_push(symtab, func);
72✔
3666

3667
   if (optional(tLPAREN)) {
72✔
3668
      if (peek() != tRPAREN)
31✔
3669
         p_tf_port_list(func);
28✔
3670
      consume(tRPAREN);
31✔
3671

3672
      consume(tSEMI);
31✔
3673

3674
      skip_over_attributes();
31✔
3675

3676
      while (scan_block_item_declaration()) {
35✔
3677
         p_block_item_declaration(func);
4✔
3678
         skip_over_attributes();
4✔
3679
      }
3680
   }
3681
   else {
3682
      consume(tSEMI);
41✔
3683

3684
      skip_over_attributes();
41✔
3685

3686
      while (scan_tf_item_declaration()) {
94✔
3687
         p_tf_item_declaration(func);
53✔
3688
         skip_over_attributes();
53✔
3689
      }
3690
   }
3691

3692
   while (not_at_token(tENDFUNCTION)) {
150✔
3693
      vlog_node_t s = p_statement_or_null();
78✔
3694
      if (s != NULL)
78✔
3695
         vlog_add_stmt(func, s);
78✔
3696
   }
3697

3698
   consume(tENDFUNCTION);
72✔
3699

3700
   if (optional(tCOLON)) {
72✔
3701
      ident_t name = p_identifier();
3✔
3702
      if (id != name)
3✔
3703
         error_at(&state.last_loc, "'%s' does not match function name '%s'",
1✔
3704
                  istr(name), istr(id));
3705
   }
3706

3707
   vlog_symtab_pop(symtab);
72✔
3708
}
72✔
3709

3710
static vlog_node_t p_function_declaration(void)
72✔
3711
{
3712
   // function [ lifetime ] function_body_declaration
3713

3714
   BEGIN("function declaration");
144✔
3715

3716
   vlog_node_t v = vlog_new(V_FUNC_DECL);
72✔
3717

3718
   consume(tFUNCTION);
72✔
3719

3720
   if (scan(tAUTOMATIC))
72✔
3721
      p_lifetime();
1✔
3722

3723
   p_function_body_declaration(v);
72✔
3724

3725
   vlog_set_loc(v, CURRENT_LOC);
72✔
3726
   return v;
72✔
3727
}
3728

3729
static vlog_node_t p_constant_param_expression(void)
387✔
3730
{
3731
   // mintypmax_expression | data_type | $
3732

3733
   BEGIN("constant parameter expression");
774✔
3734

3735
   return p_mintypmax_expression();
387✔
3736
}
3737

3738
static vlog_node_t p_param_assignment(vlog_node_t datatype, vlog_kind_t kind)
403✔
3739
{
3740
   // parameter_identifier { unpacked_dimension }
3741
   //   [ = constant_param_expression ]
3742

3743
   BEGIN("parameter assignment");
806✔
3744

3745
   vlog_node_t v = vlog_new(kind);
403✔
3746
   vlog_set_ident(v, p_identifier());
403✔
3747
   vlog_set_type(v, datatype);
403✔
3748

3749
   if (optional(tEQ))
403✔
3750
      vlog_set_value(v, p_constant_param_expression());
387✔
3751

3752
   vlog_set_loc(v, CURRENT_LOC);
403✔
3753
   return v;
403✔
3754
}
3755

3756
static void p_list_of_param_assignments(vlog_node_t parent,
341✔
3757
                                        vlog_node_t datatype,
3758
                                        vlog_kind_t kind)
3759
{
3760
   // param_assignment { , param_assignment }
3761

3762
   BEGIN("list of parameter assignments");
682✔
3763

3764
   do {
403✔
3765
      vlog_node_t v = p_param_assignment(datatype, kind);
403✔
3766
      vlog_symtab_put(symtab, v);
403✔
3767
      vlog_add_decl(parent, v);
403✔
3768
   } while (peek_nth(2) == tID && optional(tCOMMA));
403✔
3769
}
341✔
3770

3771
static void p_parameter_declaration(vlog_node_t mod)
225✔
3772
{
3773
   // parameter data_type_or_implicit list_of_param_assignments
3774

3775
   BEGIN("parameter declaration");
450✔
3776

3777
   consume(tPARAMETER);
225✔
3778

3779
   vlog_node_t dt = p_data_type_or_implicit();
225✔
3780
   p_list_of_param_assignments(mod, dt, param_kind);
225✔
3781
}
225✔
3782

3783
static void p_local_parameter_declaration(vlog_node_t mod)
114✔
3784
{
3785
   // localparam data_type_or_implicit list_of_param_assignments
3786

3787
   BEGIN("local parameter declaration");
228✔
3788

3789
   consume(tLOCALPARAM);
114✔
3790

3791
   vlog_node_t dt = p_data_type_or_implicit();
114✔
3792
   p_list_of_param_assignments(mod, dt, V_LOCALPARAM);
114✔
3793
}
114✔
3794

3795
static void p_class_property(vlog_node_t parent)
15✔
3796
{
3797
   // { property_qualifier } data_declaration
3798
   //   | const { class_item_qualifier } data_type const_identifier
3799
   //       [ = constant_expression ] ;
3800

3801
   BEGIN("class property");
30✔
3802

3803
   p_data_declaration(parent);
15✔
3804
}
15✔
3805

3806
static void p_class_constructor_arg(vlog_node_t parent)
2✔
3807
{
3808
   // tf_port_item | default
3809

3810
   BEGIN("class constructor argument");
4✔
3811

3812
   vlog_node_t v = p_tf_port_item();
2✔
3813
   vlog_symtab_put(symtab, v);
2✔
3814
   vlog_add_param(parent, v);
2✔
3815
}
2✔
3816

3817
static void p_class_constructor_arg_list(vlog_node_t parent)
2✔
3818
{
3819
   // class_constructor_arg { , class_constructor_arg }
3820

3821
   BEGIN("class constructor argument list");
4✔
3822

3823
   do {
2✔
3824
      p_class_constructor_arg(parent);
2✔
3825
   } while (optional(tCOMMA));
2✔
3826
}
2✔
3827

3828
static vlog_node_t p_class_constructor_declaration(void)
2✔
3829
{
3830
   // function [ class_scope ] new [ ( [ class_constructor_arg_list ] ) ] ;
3831
   //   { block_item_declaration }
3832
   //   [ super . new [ ( [ list_of_arguments | default ] ) ] ; ]
3833
   //   { function_statement_or_null }
3834
   //   endfunction [ : new]
3835

3836
   BEGIN("class constructor declaration");
4✔
3837

3838
   consume(tFUNCTION);
2✔
3839
   consume(tNEW);
2✔
3840

3841
   vlog_node_t v = vlog_new(V_CONSTRUCTOR);
2✔
3842
   vlog_set_ident(v, ident_new("new"));
2✔
3843

3844
   vlog_symtab_push(symtab, v);
2✔
3845

3846
   if (optional(tLPAREN)) {
2✔
3847
      if (not_at_token(tRPAREN))
2✔
3848
         p_class_constructor_arg_list(v);
2✔
3849

3850
      consume(tRPAREN);
2✔
3851
   }
3852

3853
   consume(tSEMI);
2✔
3854

3855
   skip_over_attributes();
2✔
3856

3857
   while (scan_block_item_declaration()) {
2✔
UNCOV
3858
      p_block_item_declaration(v);
×
UNCOV
3859
      skip_over_attributes();
×
3860
   }
3861

3862
   if (optional(tSUPER)) {
2✔
3863
      consume(tDOT);
1✔
3864
      consume(tNEW);
1✔
3865

3866
      vlog_node_t call = vlog_new(V_SUPER_CALL);
1✔
3867
      vlog_set_loc(call, &state.last_loc);
1✔
3868

3869
      if (optional(tLPAREN)) {
1✔
3870
         p_list_of_arguments(call);
1✔
3871
         consume(tRPAREN);
1✔
3872
      }
3873

3874
      vlog_add_stmt(v, call);
1✔
3875
   }
3876

3877
   while (not_at_token(tENDFUNCTION)) {
5✔
3878
      vlog_node_t s = p_statement_or_null();
3✔
3879
      if (s != NULL)
3✔
3880
         vlog_add_stmt(v, s);
2✔
3881
   }
3882

3883
   consume(tENDFUNCTION);
2✔
3884

3885
   if (optional(tCOLON))
2✔
3886
      consume(tNEW);
2✔
3887

3888
   vlog_symtab_pop(symtab);
2✔
3889

3890
   vlog_set_loc(v, CURRENT_LOC);
2✔
3891
   return v;
2✔
3892
}
3893

3894
static void p_method_qualifier(void)
1✔
3895
{
3896
   // [ pure ] virtual | class_item_qualifier
3897

3898
   BEGIN("method qualifier");
2✔
3899

3900
   consume(tVIRTUAL);
1✔
3901
}
1✔
3902

3903
static void p_class_method(vlog_node_t class)
3✔
3904
{
3905
   // { method_qualifier } task_declaration
3906
   //    | { method_qualifier } function_declaration
3907
   //    | pure virtual { class_item_qualifier } method_prototype ;
3908
   //    | extern { method_qualifier } method_prototype ;
3909
   //    | { method_qualifier } class_constructor_declaration
3910
   //    | extern { method_qualifier } class_constructor_prototype
3911

3912
   BEGIN("class method");
6✔
3913

3914
   if (scan(tVIRTUAL))
3✔
3915
      p_method_qualifier();
1✔
3916

3917
   switch (peek()) {
3✔
3918
   case tFUNCTION:
3✔
3919
      if (peek_nth(2) == tNEW)
3✔
3920
         vlog_add_decl(class, p_class_constructor_declaration());
2✔
3921
      else
3922
         vlog_add_decl(class, p_function_declaration());
1✔
3923
      break;
3924
   default:
×
UNCOV
3925
      one_of(tFUNCTION);
×
UNCOV
3926
      break;
×
3927
   }
3928
}
3✔
3929

3930
static void p_class_item(vlog_node_t parent)
19✔
3931
{
3932
   // { attribute_instance } class_property
3933
   //   | { attribute_instance } class_method
3934
   //   | { attribute_instance } class_constraint
3935
   //   | { attribute_instance } class_declaration
3936
   //   | { attribute_instance } covergroup_declaration
3937
   //   | local_parameter_declaration ;
3938
   //   | parameter_declaration | ;
3939

3940
   BEGIN("class item");
38✔
3941

3942
   optional_attributes();
19✔
3943

3944
   switch (peek()) {
19✔
3945
   case tSEMI:
1✔
3946
      consume(tSEMI);
1✔
3947
      break;
1✔
3948
   case tFUNCTION:
3✔
3949
   case tTASK:
3950
   case tVIRTUAL:
3951
      p_class_method(parent);
3✔
3952
      break;
3✔
3953
   default:
15✔
3954
      p_class_property(parent);
15✔
3955
      break;
15✔
3956
   }
3957
}
19✔
3958

3959
static void p_class_type(void)
2✔
3960
{
3961
   // ps_class_identifier [ parameter_value_assignment ]
3962
   //   { :: class_identifier [ parameter_value_assignment ] }
3963

3964
   BEGIN("class type");
4✔
3965

3966
   (void)p_identifier();
2✔
3967
}
2✔
3968

3969
static vlog_node_t p_class_declaration(void)
12✔
3970
{
3971
   // [ virtual ] class [ lifetime ] class_identifier [ parameter_port_list ]
3972
   //   [ extends class_type [ ( list_of_arguments ) ] ]
3973
   //   [ implements interface_class_type { , interface_class_type } ] ;
3974
   //   { class_item } endclass [ : class_identifier ]
3975

3976
   BEGIN("class declaration");
24✔
3977

3978
   vlog_node_t v = vlog_new(V_CLASS_DECL);
12✔
3979

3980
   optional(tVIRTUAL);
12✔
3981

3982
   consume(tCLASS);
12✔
3983

3984
   ident_t name = p_identifier();
12✔
3985
   vlog_set_ident(v, name);
12✔
3986

3987
   if (optional(tEXTENDS))
12✔
3988
      p_class_type();
2✔
3989

3990
   consume(tSEMI);
12✔
3991

3992
   vlog_symtab_push(symtab, v);
12✔
3993

3994
   while (not_at_token(tENDCLASS))
31✔
3995
      p_class_item(v);
19✔
3996

3997
   vlog_symtab_pop(symtab);
12✔
3998

3999
   consume(tENDCLASS);
12✔
4000

4001
   if (optional(tCOLON)) {
12✔
4002
      ident_t end_name = p_identifier();
10✔
4003
      if (name != end_name)
10✔
4004
         error_at(&state.last_loc, "'%s' does not match class name '%s'",
1✔
4005
                  istr(end_name), istr(name));
4006
   }
4007

4008
   vlog_set_loc(v, CURRENT_LOC);
12✔
4009
   vlog_symtab_put(symtab, v);
12✔
4010
   return v;
12✔
4011
}
4012

4013
static void p_block_item_declaration(vlog_node_t parent)
44✔
4014
{
4015
   // { attribute_instance } data_declaration
4016
   //   | { attribute_instance } local_parameter_declaration ;
4017
   //   | { attribute_instance } parameter_declaration ;
4018
   //   | { attribute_instance } overload_declaration
4019
   //   | { attribute_instance } let_declaration
4020

4021
   BEGIN("block item declaration");
88✔
4022

4023
   optional_attributes();
44✔
4024

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

4047
static void p_package_or_generate_item_declaration(vlog_node_t parent)
4,808✔
4048
{
4049
   // net_declaration | data_declaration | task_declaration
4050
   //   | function_declaration | checker_declaration | dpi_import_export
4051
   //   | extern_constraint_declaration | class_declaration
4052
   //   | class_constructor_declaration | local_parameter_declaration ;
4053
   //   | parameter_declaration ; | covergroup_declaration
4054
   //   | overload_declaration | assertion_item_declaration | ;
4055

4056
   BEGIN("package or generate item declaration");
9,616✔
4057

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

4127
static void p_list_of_genvar_identifiers(vlog_node_t mod, vlog_node_t dt)
14✔
4128
{
4129
   // genvar_identifier { , genvar_identifier }
4130

4131
   BEGIN("list of genvar identifiers");
28✔
4132

4133
   do {
14✔
4134
      vlog_node_t v = vlog_new(V_GENVAR_DECL);
14✔
4135
      vlog_set_ident(v, p_identifier());
14✔
4136
      vlog_set_type(v, dt);
14✔
4137
      vlog_set_loc(v, CURRENT_LOC);
14✔
4138

4139
      vlog_add_decl(mod, v);
14✔
4140

4141
      vlog_symtab_put(symtab, v);
14✔
4142
   } while (optional(tCOMMA));
14✔
4143
}
14✔
4144

4145
static void p_genvar_declaration(vlog_node_t mod)
14✔
4146
{
4147
   // genvar list_of_genvar_identifiers ;
4148

4149
   BEGIN("genvar declaration");
28✔
4150

4151
   consume(tGENVAR);
14✔
4152

4153
   vlog_node_t dt = make_integer_atom_type(DT_INTEGER);
14✔
4154
   vlog_set_flags(dt, VLOG_F_SIGNED);
14✔
4155

4156
   p_list_of_genvar_identifiers(mod, dt);
14✔
4157

4158
   consume(tSEMI);
14✔
4159
}
14✔
4160

4161
static void p_module_or_generate_item_declaration(vlog_node_t mod)
4,798✔
4162
{
4163
   // package_or_generate_item_declaration | genvar_declaration
4164
   //   | clocking_declaration | default clocking clocking_identifier ;
4165
   //   | default disable iff expression_or_dist ;
4166

4167
   BEGIN("module or generate item declaration");
9,596✔
4168

4169
   switch (peek()) {
4,798✔
4170
   case tGENVAR:
14✔
4171
      p_genvar_declaration(mod);
14✔
4172
      break;
14✔
4173
   default:
4,784✔
4174
      p_package_or_generate_item_declaration(mod);
4,784✔
4175
      break;
4,784✔
4176
   }
4177
}
4,798✔
4178

4179
static void p_generate_item(vlog_node_t parent)
134✔
4180
{
4181
   // module_or_generate_item | interface_or_generate_item
4182
   //   | checker_or_generate_item
4183

4184
   BEGIN("generate item");
268✔
4185

4186
   p_module_or_generate_item(parent);
134✔
4187
}
134✔
4188

4189
static vlog_node_t p_generate_block(void)
73✔
4190
{
4191
   // generate_item
4192
   //   | [ generate_block_identifier : ] begin [ : generate_block_identifier ]
4193
   //         { generate_item } end [ : generate_block_identifier ]
4194

4195
   BEGIN("generate block");
146✔
4196

4197
   vlog_node_t b = vlog_new(V_BLOCK);
73✔
4198

4199
   if (scan(tID, tBEGIN)) {
73✔
4200
      if (peek() == tID) {
56✔
4201
         vlog_set_ident(b, p_identifier());
1✔
4202
         consume(tCOLON);
1✔
4203
      }
4204

4205
      consume(tBEGIN);
56✔
4206

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

4216
      vlog_symtab_push(symtab, b);
56✔
4217

4218
      while (not_at_token(tEND))
154✔
4219
         p_generate_item(b);
98✔
4220

4221
      vlog_symtab_pop(symtab);
56✔
4222

4223
      consume(tEND);
56✔
4224

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

4237
   if (!vlog_has_ident(b))
73✔
4238
      vlog_set_ident(b, default_label("genblk"));
45✔
4239

4240
   vlog_set_loc(b, CURRENT_LOC);
73✔
4241
   return b;
73✔
4242
}
4243

4244
static vlog_node_t p_if_generate_construct(void)
34✔
4245
{
4246
   // if ( constant_expression ) generate_block
4247
   //   { else if ( constant_expression ) generate_block }
4248
   //   [ else generate_block ]
4249

4250
   BEGIN("if generate construct");
68✔
4251

4252
   vlog_node_t v = vlog_new(V_IF_GENERATE);
34✔
4253

4254
   consume(tIF);
34✔
4255
   consume(tLPAREN);
34✔
4256

4257
   vlog_node_t c0 = vlog_new(V_COND);
34✔
4258
   vlog_set_value(c0, p_constant_expression());
34✔
4259

4260
   consume(tRPAREN);
34✔
4261

4262
   vlog_set_loc(c0, CURRENT_LOC);
34✔
4263
   vlog_add_stmt(c0, p_generate_block());
34✔
4264

4265
   vlog_add_cond(v, c0);
34✔
4266

4267
   while (optional(tELSE)) {
44✔
4268
      if (peek() == tIF) {
21✔
4269
         // else if ( constant_expression ) generate_block
4270
         consume(tIF);
10✔
4271
         consume(tLPAREN);
10✔
4272

4273
         vlog_node_t cn = vlog_new(V_COND);
10✔
4274
         vlog_set_value(cn, p_constant_expression());
10✔
4275

4276
         consume(tRPAREN);
10✔
4277

4278
         vlog_set_loc(cn, CURRENT_LOC);
10✔
4279
         vlog_add_stmt(cn, p_generate_block());
10✔
4280

4281
         vlog_add_cond(v, cn);
10✔
4282
      }
4283
      else {
4284
         // else generate_block (no condition = default branch)
4285
         vlog_node_t ce = vlog_new(V_COND);
11✔
4286
         vlog_set_loc(ce, &state.last_loc);
11✔
4287
         vlog_add_stmt(ce, p_generate_block());
11✔
4288

4289
         vlog_add_cond(v, ce);
11✔
4290
         break;
11✔
4291
      }
4292
   }
4293

4294
   vlog_set_loc(v, CURRENT_LOC);
34✔
4295
   return v;
34✔
4296
}
4297

4298
static vlog_node_t p_case_generate_construct(void)
1✔
4299
{
4300
   // case ( constant_expression )
4301
   //   case_generate_item { case_generate_item } endcase
4302
   //
4303
   // Lowered to V_IF_GENERATE with equality comparisons so the existing
4304
   // simplifier and elaborator handle it without a new node kind.
4305

4306
   BEGIN("case generate construct");
2✔
4307

4308
   consume(tCASE);
1✔
4309
   consume(tLPAREN);
1✔
4310

4311
   vlog_node_t selector = p_constant_expression();
1✔
4312

4313
   consume(tRPAREN);
1✔
4314

4315
   vlog_node_t v = vlog_new(V_IF_GENERATE);
1✔
4316

4317
   while (not_at_token(tENDCASE)) {
4✔
4318
      vlog_node_t cn = vlog_new(V_COND);
3✔
4319

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

4337
            if (cond == NULL) {
3✔
4338
               cond = eq;
4339
            }
4340
            else {
4341
               vlog_node_t lor = vlog_new(V_BINARY);
×
4342
               vlog_set_subkind(lor, V_BINARY_LOG_OR);
×
4343
               vlog_set_left(lor, cond);
×
4344
               vlog_set_right(lor, eq);
×
UNCOV
4345
               vlog_set_loc(lor, CURRENT_LOC);
×
UNCOV
4346
               cond = lor;
×
4347
            }
4348
         } while (optional(tCOMMA));
3✔
4349

4350
         consume(tCOLON);
3✔
4351
         vlog_set_value(cn, cond);
3✔
4352
      }
4353

4354
      vlog_set_loc(cn, CURRENT_LOC);
3✔
4355
      vlog_add_stmt(cn, p_generate_block());
3✔
4356
      vlog_add_cond(v, cn);
3✔
4357
   }
4358

4359
   consume(tENDCASE);
1✔
4360

4361
   vlog_set_loc(v, CURRENT_LOC);
1✔
4362
   return v;
1✔
4363
}
4364

4365
static vlog_node_t p_conditional_generate_construct(void)
35✔
4366
{
4367
   // if_generate_construct | case_generate_construct
4368

4369
   BEGIN("conditional generate construct");
70✔
4370

4371
   switch (peek()) {
35✔
4372
   case tIF:
34✔
4373
      return p_if_generate_construct();
34✔
4374
   case tCASE:
1✔
4375
      return p_case_generate_construct();
1✔
UNCOV
4376
   default:
×
4377
      should_not_reach_here();
4378
   }
4379
}
4380

4381
static vlog_node_t p_genvar_initialization(void)
15✔
4382
{
4383
   // [ genvar ] genvar_identifier = constant_expression
4384

4385
   BEGIN("genvar initialization");
30✔
4386

4387
   vlog_node_t v = vlog_new(V_FOR_INIT);
15✔
4388

4389
   vlog_node_t ref = vlog_new(V_REF);
15✔
4390
   vlog_set_ident(ref, p_identifier());
15✔
4391
   vlog_set_loc(ref, &state.last_loc);
15✔
4392

4393
   vlog_symtab_lookup(symtab, ref);
15✔
4394

4395
   consume(tEQ);
15✔
4396

4397
   vlog_node_t a = vlog_new(V_BASSIGN);
15✔
4398
   vlog_set_target(a, ref);
15✔
4399
   vlog_set_value(a, p_constant_expression());
15✔
4400
   vlog_set_loc(a, CURRENT_LOC);
15✔
4401

4402
   vlog_add_stmt(v, a);
15✔
4403

4404
   vlog_set_loc(v, CURRENT_LOC);
15✔
4405
   return v;
15✔
4406
}
4407

4408
static vlog_node_t p_genvar_iteration(void)
15✔
4409
{
4410
   // genvar_identifier assignment_operator genvar_expression
4411
   //   | inc_or_dec_operator genvar_identifier
4412
   //   | genvar_identifier inc_or_dec_operator
4413

4414
   BEGIN("genvar iteration");
30✔
4415

4416
   vlog_node_t v = vlog_new(V_FOR_STEP);
15✔
4417

4418
   vlog_node_t prefix = NULL;
15✔
4419
   if (scan(tPLUSPLUS, tMINUSMINUS)) {
15✔
4420
      prefix = vlog_new(V_PREFIX);
1✔
4421
      vlog_set_subkind(prefix, p_inc_or_dec_operator());
1✔
4422
   }
4423

4424
   vlog_node_t ref = vlog_new(V_REF);
15✔
4425
   vlog_set_ident(ref, p_identifier());
15✔
4426
   vlog_set_loc(ref, &state.last_loc);
15✔
4427

4428
   vlog_symtab_lookup(symtab, ref);
15✔
4429

4430
   if (prefix != NULL) {
15✔
4431
      vlog_set_target(prefix, ref);
1✔
4432

4433
      vlog_add_stmt(v, prefix);
1✔
4434
   }
4435
   else if (optional(tEQ)) {
14✔
4436
      vlog_node_t a = vlog_new(V_BASSIGN);
13✔
4437
      vlog_set_target(a, ref);
13✔
4438
      vlog_set_value(a, p_constant_expression());
13✔
4439

4440
      vlog_add_stmt(v, a);
13✔
4441
   }
4442
   else {
4443
      vlog_node_t a = vlog_new(V_POSTFIX);
1✔
4444
      vlog_set_subkind(a, p_inc_or_dec_operator());
1✔
4445
      vlog_set_target(a, ref);
1✔
4446

4447
      vlog_add_stmt(v, a);
1✔
4448
   }
4449

4450
   vlog_set_loc(v, CURRENT_LOC);
15✔
4451
   return v;
15✔
4452
}
4453

4454
static vlog_node_t p_loop_generate_construct(void)
15✔
4455
{
4456
   // for ( genvar_initialization ; genvar_expression ; genvar_iteration )
4457
   //   generate_block
4458

4459
   BEGIN("loop generate construct");
30✔
4460

4461
   consume(tFOR);
15✔
4462
   consume(tLPAREN);
15✔
4463

4464
   vlog_node_t v = vlog_new(V_FOR_GENERATE);
15✔
4465

4466
   vlog_symtab_push(symtab, v);
15✔
4467

4468
   vlog_set_left(v, p_genvar_initialization());
15✔
4469

4470
   consume(tSEMI);
15✔
4471

4472
   vlog_set_value(v, p_constant_expression());
15✔
4473

4474
   consume(tSEMI);
15✔
4475

4476
   vlog_set_right(v, p_genvar_iteration());
15✔
4477

4478
   consume(tRPAREN);
15✔
4479

4480
   vlog_add_stmt(v, p_generate_block());
15✔
4481

4482
   vlog_symtab_pop(symtab);
15✔
4483

4484
   vlog_set_loc(v, CURRENT_LOC);
15✔
4485
   return v;
15✔
4486
}
4487

4488
static void p_module_common_item(vlog_node_t mod)
6,531✔
4489
{
4490
   // module_or_generate_item_declaration
4491
   //   | interface_instantiation | program_instantiation
4492
   //   | assertion_item | bind_directive | continuous_assign
4493
   //   | net_alias | initial_construct | final_construct
4494
   //   | always_construct | loop_generate_construct
4495
   //   | conditional_generate_construct | elaboration_system_task
4496

4497
   BEGIN("module common item");
13,062✔
4498

4499
   switch (peek()) {
6,531✔
4500
   case tALWAYS:
310✔
4501
   case tALWAYSCOMB:
4502
   case tALWAYSFF:
4503
   case tALWAYSLATCH:
4504
      vlog_add_stmt(mod, p_always_construct());
310✔
4505
      break;
310✔
4506
   case tINITIAL:
744✔
4507
      vlog_add_stmt(mod, p_initial_construct());
744✔
4508
      break;
744✔
4509
   case tWIRE:
4,771✔
4510
   case tUWIRE:
4511
   case tSUPPLY0:
4512
   case tSUPPLY1:
4513
   case tTRI:
4514
   case tTRI0:
4515
   case tTRI1:
4516
   case tTRIAND:
4517
   case tTRIOR:
4518
   case tTRIREG:
4519
   case tWAND:
4520
   case tWOR:
4521
   case tINTERCONNECT:
4522
   case tREG:
4523
   case tSTRUCT:
4524
   case tUNION:
4525
   case tTYPEDEF:
4526
   case tENUM:
4527
   case tSVINT:
4528
   case tINTEGER:
4529
   case tSVREAL:
4530
   case tSHORTREAL:
4531
   case tREALTIME:
4532
   case tTIME:
4533
   case tTASK:
4534
   case tFUNCTION:
4535
   case tLOCALPARAM:
4536
   case tPARAMETER:
4537
   case tEVENT:
4538
   case tID:
4539
   case tGENVAR:
4540
   case tVAR:
4541
   case tLOGIC:
4542
   case tBIT:
4543
   case tSHORTINT:
4544
   case tLONGINT:
4545
   case tBYTE:
4546
   case tSTRINGK:
4547
   case tIMPORT:
4548
      p_module_or_generate_item_declaration(mod);
4,771✔
4549
      break;
4,771✔
4550
   case tASSIGN:
656✔
4551
      p_continuous_assign(mod);
656✔
4552
      break;
656✔
4553
   case tFOR:
15✔
4554
      vlog_add_stmt(mod, p_loop_generate_construct());
15✔
4555
      break;
15✔
4556
   case tIF:
35✔
4557
   case tCASE:
4558
      vlog_add_stmt(mod, p_conditional_generate_construct());
35✔
4559
      break;
35✔
UNCOV
4560
   default:
×
UNCOV
4561
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
×
4562
             tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
4563
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM,
4564
             tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTIME, tTASK,
4565
             tFUNCTION, tPARAMETER, tLOCALPARAM, tEVENT, tID, tGENVAR, tVAR,
4566
             tLOGIC, tBIT, tSHORTINT, tLONGINT, tBYTE, tSTRINGK, tIMPORT,
4567
             tASSIGN, tFOR, tIF);
UNCOV
4568
      drop_tokens_until(&state, tSEMI);
×
4569
   }
4570
}
6,531✔
4571

4572
static vlog_strength_t p_strength0(void)
58✔
4573
{
4574
   // supply0 | strong0 | pull0 | weak0
4575

4576
   BEGIN("strength0");
116✔
4577

4578
   switch (one_of(tSUPPLY0, tSTRONG0, tPULL0, tWEAK0)) {
58✔
4579
   default:
4580
   case tSUPPLY0: return V_STRENGTH_SUPPLY;
4581
   case tSTRONG0: return V_STRENGTH_STRONG;
4582
   case tPULL0:   return V_STRENGTH_PULL;
4583
   case tWEAK0:   return V_STRENGTH_WEAK;
4584
   }
4585
}
4586

4587
static vlog_strength_t p_strength1(void)
60✔
4588
{
4589
   // supply1 | strong1 | pull1 | weak1
4590

4591
   BEGIN("strength1");
120✔
4592

4593
   switch (one_of(tSUPPLY1, tSTRONG1, tPULL1, tWEAK1)) {
60✔
4594
   default:
4595
   case tSUPPLY1: return V_STRENGTH_SUPPLY;
4596
   case tSTRONG1: return V_STRENGTH_STRONG;
4597
   case tPULL1:   return V_STRENGTH_PULL;
4598
   case tWEAK1:   return V_STRENGTH_WEAK;
4599
   }
4600
}
4601

4602
static vlog_node_t p_pulldown_strength(void)
2✔
4603
{
4604
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength0 )
4605

4606
   BEGIN("pulldown strength");
4✔
4607

4608
   consume(tLPAREN);
2✔
4609

4610
   vlog_strength_t s0, s1;
2✔
4611
   switch (peek()) {
2✔
UNCOV
4612
   case tSUPPLY1:
×
4613
   case tSTRONG1:
4614
   case tPULL1:
4615
   case tWEAK1:
4616
      s1 = p_strength1();
×
4617
      consume(tCOMMA);
×
UNCOV
4618
      s0 = p_strength0();
×
UNCOV
4619
      break;
×
4620
   default:
2✔
4621
      s0 = s1 = p_strength0();
2✔
4622
      if (optional(tCOMMA))
2✔
UNCOV
4623
         s1 = p_strength1();
×
4624
      break;
4625
   }
4626

4627
   consume(tRPAREN);
2✔
4628

4629
   vlog_node_t v = vlog_new(V_STRENGTH);
2✔
4630
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
2✔
4631
   vlog_set_loc(v, CURRENT_LOC);
2✔
4632
   return v;
2✔
4633
}
4634

4635
static vlog_node_t p_pullup_strength(void)
7✔
4636
{
4637
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength1 )
4638

4639
   BEGIN("pullup strength");
14✔
4640

4641
   consume(tLPAREN);
7✔
4642

4643
   vlog_strength_t s0, s1;
7✔
4644
   switch (peek()) {
7✔
4645
   case tSUPPLY0:
1✔
4646
   case tSTRONG0:
4647
   case tPULL0:
4648
   case tWEAK0:
4649
      s0 = p_strength0();
1✔
4650
      consume(tCOMMA);
1✔
4651
      s1 = p_strength1();
1✔
4652
      break;
1✔
4653
   default:
6✔
4654
      s1 = s0 = p_strength1();
6✔
4655
      if (optional(tCOMMA))
6✔
4656
         s0 = p_strength0();
1✔
4657
      break;
4658
   }
4659

4660
   consume(tRPAREN);
7✔
4661

4662
   vlog_node_t v = vlog_new(V_STRENGTH);
7✔
4663
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
7✔
4664
   vlog_set_loc(v, CURRENT_LOC);
7✔
4665
   return v;
7✔
4666
}
4667

4668
static vlog_node_t p_pull_gate_instance(vlog_gate_kind_t kind, vlog_node_t st)
22✔
4669
{
4670
   // [ name_of_instance ] ( output_terminal )
4671

4672
   BEGIN("pull gate instance");
44✔
4673

4674
   vlog_node_t v = vlog_new(V_GATE_INST);
22✔
4675
   vlog_set_subkind(v, kind);
22✔
4676
   vlog_add_param(v, st);
22✔
4677

4678
   if (peek() == tID) {
22✔
4679
      vlog_set_ident(v, p_identifier());
7✔
4680
      vlog_set_loc(v, &state.last_loc);
7✔
4681
      vlog_symtab_put(symtab, v);
7✔
4682
   }
4683
   else
4684
      vlog_set_ident(v, default_label("gate"));
15✔
4685

4686
   consume(tLPAREN);
22✔
4687

4688
   vlog_symtab_set_implicit(symtab, implicit_kind);
22✔
4689

4690
   vlog_set_target(v, p_net_lvalue());
22✔
4691

4692
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
22✔
4693

4694
   consume(tRPAREN);
22✔
4695

4696
   vlog_set_loc(v, CURRENT_LOC);
22✔
4697
   return v;
22✔
4698
}
4699

4700
static vlog_node_t p_n_terminal_gate_instance(vlog_gate_kind_t kind,
43✔
4701
                                              vlog_node_t st)
4702
{
4703
   // [ name_of_instance ] ( output_terminal , input_terminal
4704
   //     { , input_terminal } )
4705

4706
   BEGIN("N-terminal gate instance");
86✔
4707

4708
   vlog_node_t v = vlog_new(V_GATE_INST);
43✔
4709
   vlog_set_subkind(v, kind);
43✔
4710

4711
   if (peek() == tID) {
43✔
4712
      vlog_set_ident(v, p_identifier());
5✔
4713
      vlog_set_loc(v, &state.last_loc);
5✔
4714
      vlog_symtab_put(symtab, v);
5✔
4715
   }
4716
   else
4717
      vlog_set_ident(v, default_label("gate"));
38✔
4718

4719
   consume(tLPAREN);
43✔
4720

4721
   vlog_symtab_set_implicit(symtab, implicit_kind);
43✔
4722

4723
   vlog_set_target(v, p_net_lvalue());
43✔
4724

4725
   consume(tCOMMA);
43✔
4726

4727
   do {
64✔
4728
      vlog_add_param(v, p_expression());
64✔
4729
   } while (optional(tCOMMA));
64✔
4730

4731
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
43✔
4732

4733
   consume(tRPAREN);
43✔
4734

4735
   vlog_set_loc(v, CURRENT_LOC);
43✔
4736
   return v;
43✔
4737
}
4738

4739
static vlog_node_t p_enable_gate_instance(vlog_gate_kind_t kind)
1✔
4740
{
4741
   // [ name_of_instance ] ( output_terminal , input_terminal ,
4742
   //     enable_terminal )
4743

4744
   BEGIN("enable gate instance");
2✔
4745

4746
   vlog_node_t v = vlog_new(V_GATE_INST);
1✔
4747
   vlog_set_subkind(v, kind);
1✔
4748

4749
   if (peek() == tID) {
1✔
4750
      vlog_set_ident(v, p_identifier());
×
UNCOV
4751
      vlog_set_loc(v, &state.last_loc);
×
UNCOV
4752
      vlog_symtab_put(symtab, v);
×
4753
   }
4754
   else
4755
      vlog_set_ident(v, default_label("gate"));
1✔
4756

4757
   consume(tLPAREN);
1✔
4758

4759
   vlog_symtab_set_implicit(symtab, implicit_kind);
1✔
4760

4761
   vlog_set_target(v, p_net_lvalue());
1✔
4762

4763
   consume(tCOMMA);
1✔
4764

4765
   vlog_add_param(v, p_expression());
1✔
4766

4767
   consume(tCOMMA);
1✔
4768

4769
   vlog_add_param(v, p_expression());
1✔
4770

4771
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
1✔
4772

4773
   consume(tRPAREN);
1✔
4774

4775
   vlog_set_loc(v, CURRENT_LOC);
1✔
4776
   return v;
1✔
4777
}
4778

4779
static vlog_node_t p_pass_switch_instance(vlog_gate_kind_t kind)
1✔
4780
{
4781
   // [ name_of_instance ] ( inout_terminal , inout_terminal )
4782

4783
   BEGIN("pass switch instance");
2✔
4784

4785
   vlog_node_t v = vlog_new(V_GATE_INST);
1✔
4786
   vlog_set_subkind(v, kind);
1✔
4787

4788
   if (peek() == tID) {
1✔
4789
      vlog_set_ident(v, p_identifier());
×
UNCOV
4790
      vlog_set_loc(v, &state.last_loc);
×
UNCOV
4791
      vlog_symtab_put(symtab, v);
×
4792
   }
4793
   else
4794
      vlog_set_ident(v, default_label("gate"));
1✔
4795

4796
   consume(tLPAREN);
1✔
4797

4798
   vlog_symtab_set_implicit(symtab, implicit_kind);
1✔
4799

4800
   vlog_set_target(v, p_net_lvalue());
1✔
4801

4802
   consume(tCOMMA);
1✔
4803

4804
   vlog_add_param(v, p_net_lvalue());
1✔
4805

4806
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
1✔
4807

4808
   consume(tRPAREN);
1✔
4809

4810
   vlog_set_loc(v, CURRENT_LOC);
1✔
4811
   return v;
1✔
4812
}
4813

4814
static vlog_node_t p_pass_enable_switch_instance(vlog_gate_kind_t kind)
1✔
4815
{
4816
   // [ name_of_instance ] ( inout_terminal , inout_terminal ,
4817
   //     enable_terminal )
4818

4819
   BEGIN("pass enable switch instance");
2✔
4820

4821
   vlog_node_t v = vlog_new(V_GATE_INST);
1✔
4822
   vlog_set_subkind(v, kind);
1✔
4823

4824
   if (peek() == tID) {
1✔
4825
      vlog_set_ident(v, p_identifier());
×
UNCOV
4826
      vlog_set_loc(v, &state.last_loc);
×
UNCOV
4827
      vlog_symtab_put(symtab, v);
×
4828
   }
4829
   else
4830
      vlog_set_ident(v, default_label("gate"));
1✔
4831

4832
   consume(tLPAREN);
1✔
4833

4834
   vlog_symtab_set_implicit(symtab, implicit_kind);
1✔
4835

4836
   vlog_set_target(v, p_net_lvalue());
1✔
4837

4838
   consume(tCOMMA);
1✔
4839

4840
   vlog_add_param(v, p_net_lvalue());
1✔
4841

4842
   consume(tCOMMA);
1✔
4843

4844
   vlog_add_param(v, p_expression());
1✔
4845

4846
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
1✔
4847

4848
   consume(tRPAREN);
1✔
4849

4850
   vlog_set_loc(v, CURRENT_LOC);
1✔
4851
   return v;
1✔
4852
}
4853

4854
static void p_gate_instantiation(vlog_node_t mod)
68✔
4855
{
4856
   // cmos_switchtype [ delay3 ] cmos_switch_instance
4857
   //     { , cmos_switch_instance } ;
4858
   //  | enable_gatetype [ drive_strength ] [ delay3 ]
4859
   //     enable_gate_instance { , enable_gate_instance } ;
4860
   //  | mos_switchtype [ delay3 ] mos_switch_instance
4861
   //     { , mos_switch_instance } ;
4862
   //  | n_input_gatetype [ drive_strength ] [ delay2 ] n_input_gate_instance
4863
   //     { , n_input_gate_instance } ;
4864
   //  | n_output_gatetype [ drive_strength ] [ delay2 ] n_output_gate_instance
4865
   //     { , n_output_gate_instance } ;
4866
   //  | pass_en_switchtype [ delay2 ] pass_enable_switch_instance
4867
   //     { , pass_enable_switch_instance } ;
4868
   //  | pass_switchtype pass_switch_instance { , pass_switch_instance } ;
4869
   //  | pulldown [ pulldown_strength ] pull_gate_instance
4870
   //     { , pull_gate_instance } ;
4871
   //  | pullup [ pullup_strength ] pull_gate_instance
4872
   //     { , pull_gate_instance } ;
4873

4874
   BEGIN("gate instantiation");
136✔
4875

4876
   token_t token = one_of(tPULLDOWN, tPULLUP, tAND, tNAND, tOR, tNOR,
68✔
4877
                          tXOR, tXNOR, tNOT, tBUF, tBUFIF0, tBUFIF1,
4878
                          tNOTIF0, tNOTIF1, tTRAN, tRTRAN, tTRANIF0, tTRANIF1,
4879
                          tRTRANIF0, tRTRANIF1);
4880

4881
   switch (token) {
68✔
4882
   case tPULLDOWN:
8✔
4883
      {
4884
         vlog_node_t st;
8✔
4885
         if (peek() == tLPAREN && peek_nth(2) != tID)
8✔
4886
            st = p_pulldown_strength();
2✔
4887
         else {
4888
            st = vlog_new(V_STRENGTH);
6✔
4889
            vlog_set_subkind(st, ST_PULLUP);
6✔
4890
         }
4891

4892
         do {
8✔
4893
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLDOWN, st);
8✔
4894
            vlog_add_stmt(mod, g);
8✔
4895
         } while (optional(tCOMMA));
8✔
4896
      }
4897
      break;
4898

4899
   case tPULLUP:
14✔
4900
      {
4901
         vlog_node_t st;
14✔
4902
         if (peek() == tLPAREN && peek_nth(2) != tID)
14✔
4903
            st = p_pullup_strength();
7✔
4904
         else {
4905
            st = vlog_new(V_STRENGTH);
7✔
4906
            vlog_set_subkind(st, ST_PULLUP);
7✔
4907
         }
4908

4909
         do {
14✔
4910
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLUP, st);
14✔
4911
            vlog_add_stmt(mod, g);
14✔
4912
         } while (optional(tCOMMA));
14✔
4913
      }
4914
      break;
4915

4916
   case tAND:
43✔
4917
   case tNAND:
4918
   case tOR:
4919
   case tNOR:
4920
   case tXOR:
4921
   case tXNOR:
4922
   case tNOT:
4923
   case tBUF:
4924
      {
4925
         vlog_node_t st;
43✔
4926
         if (peek() == tLPAREN && peek_nth(2) != tID)
43✔
4927
            st = p_drive_strength();
1✔
4928
         else {
4929
            st = vlog_new(V_STRENGTH);
42✔
4930
            vlog_set_subkind(st, ST_STRONG);
42✔
4931
         }
4932

4933
         const vlog_gate_kind_t kind = get_gate_kind(token);
43✔
4934

4935
         if (peek() == tHASH)
43✔
4936
            p_delay2();
2✔
4937

4938
         do {
43✔
4939
            vlog_add_stmt(mod, p_n_terminal_gate_instance(kind, st));
43✔
4940
         } while (optional(tCOMMA));
43✔
4941
      }
4942
      break;
4943

4944
   case tBUFIF0:
1✔
4945
   case tBUFIF1:
4946
   case tNOTIF0:
4947
   case tNOTIF1:
4948
      {
4949
         vlog_node_t st;
1✔
4950
         if (peek() == tLPAREN && peek_nth(2) != tID)
1✔
4951
            st = p_drive_strength();
1✔
4952
         else {
UNCOV
4953
            st = vlog_new(V_STRENGTH);
×
UNCOV
4954
            vlog_set_subkind(st, ST_STRONG);
×
4955
         }
4956

4957
         if (peek() == tHASH)
1✔
UNCOV
4958
            p_delay3();
×
4959

4960
         const vlog_gate_kind_t kind = get_gate_kind(token);
1✔
4961

4962
         do {
1✔
4963
            vlog_add_stmt(mod, p_enable_gate_instance(kind));
1✔
4964
         } while (optional(tCOMMA));
1✔
4965
      }
4966
      break;
4967

4968
   case tTRAN:
1✔
4969
   case tRTRAN:
4970
      {
4971
         const vlog_gate_kind_t kind = get_gate_kind(token);
1✔
4972

4973
         do {
1✔
4974
            vlog_add_stmt(mod, p_pass_switch_instance(kind));
1✔
4975
         } while (optional(tCOMMA));
1✔
4976
      }
4977
      break;
4978

4979
   case tTRANIF0:
1✔
4980
   case tTRANIF1:
4981
   case tRTRANIF0:
4982
   case tRTRANIF1:
4983
      {
4984
         if (peek() == tHASH)
1✔
UNCOV
4985
            p_delay2();
×
4986

4987
         const vlog_gate_kind_t kind = get_gate_kind(token);
1✔
4988

4989
         do {
1✔
4990
            vlog_add_stmt(mod, p_pass_enable_switch_instance(kind));
1✔
4991
         } while (optional(tCOMMA));
1✔
4992
      }
4993
      break;
4994

4995
   default:
4996
      break;
4997
   }
4998

4999
   consume(tSEMI);
68✔
5000
}
68✔
5001

5002
static vlog_node_t p_module_path_expression(void)
4✔
5003
{
5004
   // module_path_primary
5005
   //   | unary_module_path_operator { attribute_instance } module_path_primary
5006
   //   | module_path_expression binary_module_path_operator
5007
   //      { attribute_instance } module_path_expression
5008
   //   | module_path_conditional_expression
5009

5010
   BEGIN("module path expression");
8✔
5011

5012
   // TODO: sem should check valid subset
5013
   return p_expression();
4✔
5014
}
5015

5016
static void p_path_delay_expression(void)
22✔
5017
{
5018
   // constant_expression
5019
   //   | constant_expression : constant_expression : constant_expression
5020

5021
   BEGIN("path delay expression");
44✔
5022

5023
   (void)p_constant_expression();
22✔
5024
}
22✔
5025

5026
static void p_list_of_path_delay_expressions(void)
18✔
5027
{
5028
   // path_delay_expression { , path_delay_expression }
5029

5030
   BEGIN("list of path delay expressions");
36✔
5031

5032
   do {
22✔
5033
      p_path_delay_expression();
22✔
5034
   } while (optional(tCOMMA));
22✔
5035
}
18✔
5036

5037
static void p_path_delay_value(void)
18✔
5038
{
5039
   // list_of_path_delay_expressions | ( list_of_path_delay_expressions )
5040

5041
   BEGIN("path delay value");
36✔
5042

5043
   if (optional(tLPAREN)) {
18✔
5044
      p_list_of_path_delay_expressions();
4✔
5045
      consume(tRPAREN);
4✔
5046
   }
5047
   else
5048
      p_list_of_path_delay_expressions();
14✔
5049
}
18✔
5050

5051
static vlog_node_t p_specify_terminal_descriptor(void)
76✔
5052
{
5053
   // identifier [ [ constant_range_expression ] ]
5054

5055
   BEGIN("specify terminal descriptor");
152✔
5056

5057
   vlog_node_t v = vlog_new(V_REF);
76✔
5058
   vlog_set_ident(v, p_identifier());
76✔
5059
   vlog_set_loc(v, CURRENT_LOC);
76✔
5060

5061
   if (optional(tLSQUARE)) {
76✔
5062
      (void)p_constant_range_expression();
2✔
5063
      consume(tRSQUARE);
2✔
5064
   }
5065

5066
   return v;
76✔
5067
}
5068

5069
static void p_list_of_path_inputs(vlog_node_t v, vlog_node_t head)
8✔
5070
{
5071
   // specify_input_terminal_descriptor { , specify_input_terminal_descriptor }
5072

5073
   BEGIN_WITH_HEAD("list of path inputs", head);
16✔
5074

5075
   while (optional(tCOMMA))
15✔
5076
      (void)p_specify_terminal_descriptor();
7✔
5077
}
8✔
5078

5079
static void p_list_of_path_outputs(vlog_node_t v)
8✔
5080
{
5081
   // specify_output_terminal_descriptor
5082
   //     { , specify_output_terminal_descriptor }
5083

5084
   BEGIN("list of path outputs");
16✔
5085

5086
   do {
17✔
5087
      (void)p_specify_terminal_descriptor();
17✔
5088
   } while (optional(tCOMMA));
17✔
5089
}
8✔
5090

5091
static void p_polarity_operator(void)
9✔
5092
{
5093
   // + | -
5094

5095
   BEGIN("polarity operator");
18✔
5096

5097
   (void)one_of(tPLUS, tMINUS);
9✔
5098
}
9✔
5099

5100
static vlog_node_t p_parallel_path_description(vlog_node_t head)
8✔
5101
{
5102
   // ( specify_input_terminal_descriptor [ polarity_operator ]
5103
   //     => specify_output_terminal_descriptor )
5104

5105
   EXTEND("parallel path description");
16✔
5106

5107
   if (scan(tPLUS, tMINUS))
8✔
5108
      (void)p_polarity_operator();
3✔
5109

5110
   consume(tASSOC);
8✔
5111

5112
   (void)p_specify_terminal_descriptor();
8✔
5113

5114
   consume(tRPAREN);
8✔
5115
   return NULL;
8✔
5116
}
5117

5118
static vlog_node_t p_full_path_description(vlog_node_t head)
3✔
5119
{
5120
   // ( list_of_path_inputs [ polarity_operator ] *> list_of_path_outputs )
5121

5122
   EXTEND("full path description");
6✔
5123

5124
   p_list_of_path_inputs(NULL, head);
3✔
5125

5126
   if (scan(tPLUS, tMINUS))
3✔
5127
      (void)p_polarity_operator();
3✔
5128

5129
   consume(tTIMESGT);
3✔
5130

5131
   p_list_of_path_outputs(NULL);
3✔
5132

5133
   consume(tRPAREN);
3✔
5134
   return NULL;
3✔
5135
}
5136

5137
static vlog_node_t p_simple_path_declaration(void)
11✔
5138
{
5139
   // parallel_path_description = path_delay_value
5140
   //   | full_path_description = path_delay_value
5141

5142
   BEGIN("simple path declaration");
22✔
5143

5144
   // Parse up to the first terminal descriptor to determine which
5145
   // production to use
5146

5147
   consume(tLPAREN);
11✔
5148

5149
   vlog_node_t head = p_specify_terminal_descriptor();
11✔
5150

5151
   if (scan(tCOMMA, tTIMESGT) || peek_nth(2) == tTIMESGT)
11✔
5152
      (void)p_full_path_description(head);
3✔
5153
   else
5154
      (void)p_parallel_path_description(head);
8✔
5155

5156
   consume(tEQ);
11✔
5157

5158
   (void)p_path_delay_value();
11✔
5159

5160
   return NULL;
11✔
5161
}
5162

5163
static void p_edge_identifier(void)
7✔
5164
{
5165
   // posedge | negedge | edge
5166

5167
   BEGIN("edge identifier");
14✔
5168

5169
   one_of(tPOSEDGE, tNEGEDGE, tEDGE);
7✔
5170
}
7✔
5171

5172
static vlog_node_t p_parallel_edge_sensitive_path_description(vlog_node_t head)
2✔
5173
{
5174
   // ( [ edge_identifier ] specify_input_terminal_descriptor
5175
   //     [ polarity_operator ] => ( specify_output_terminal_descriptor
5176
   //     [ polarity_operator ] : data_source_expression ) )
5177

5178
   EXTEND("parallel edge sensitive path description");
4✔
5179

5180
   if (scan(tPLUS, tMINUS))
2✔
UNCOV
5181
      (void)p_polarity_operator();
×
5182

5183
   consume(tASSOC);
2✔
5184

5185
   consume(tLPAREN);
2✔
5186

5187
   (void)p_specify_terminal_descriptor();
2✔
5188

5189
   if (scan(tPLUS, tMINUS)) {
2✔
UNCOV
5190
      (void)p_polarity_operator();
×
UNCOV
5191
      consume(tCOLON);
×
5192
   }
5193
   else if (scan(tINDEXPOS, tINDEXNEG))
2✔
5194
      consume(peek());  // Lexing ambiguity with +: and -:
1✔
5195
   else
5196
      consume(tCOLON);
1✔
5197

5198
   (void)p_expression();
2✔
5199

5200
   consume(tRPAREN);
2✔
5201
   consume(tRPAREN);
2✔
5202
   return NULL;
2✔
5203
}
5204

5205
static vlog_node_t p_full_edge_sensitive_path_description(vlog_node_t head)
5✔
5206
{
5207
   // ( [ edge_identifier ] list_of_path_inputs [ polarity_operator ] *>
5208
   //     ( list_of_path_outputs [ polarity_operator ]
5209
   //     : data_source_expression ) )
5210

5211
   EXTEND("full edge sensitive path description");
10✔
5212

5213
   p_list_of_path_inputs(NULL, head);
5✔
5214

5215
   if (scan(tPLUS, tMINUS))
5✔
5216
      (void)p_polarity_operator();
3✔
5217

5218
   consume(tTIMESGT);
5✔
5219

5220
   consume(tLPAREN);
5✔
5221

5222
   p_list_of_path_outputs(NULL);
5✔
5223

5224
   if (scan(tPLUS, tMINUS)) {
5✔
UNCOV
5225
      (void)p_polarity_operator();
×
UNCOV
5226
      consume(tCOLON);
×
5227
   }
5228
   else if (scan(tINDEXPOS, tINDEXNEG))
5✔
5229
      consume(peek());  // Lexing ambiguity with +: and -:
2✔
5230
   else
5231
      consume(tCOLON);
3✔
5232

5233
   (void)p_expression();
5✔
5234

5235
   consume(tRPAREN);
5✔
5236
   consume(tRPAREN);
5✔
5237
   return NULL;
5✔
5238
}
5239

5240
static vlog_node_t p_edge_sensitive_path_declaration(void)
7✔
5241
{
5242
   // parallel_edge_sensitive_path_description = path_delay_value
5243
   //   | full_edge_sensitive_path_description = path_delay_value
5244

5245
   BEGIN("edge sensitive path declaration");
14✔
5246

5247
   // Parse up to the first terminal descriptor to determine which
5248
   // production to use
5249

5250
   consume(tLPAREN);
7✔
5251

5252
   if (scan(tEDGE, tPOSEDGE, tNEGEDGE))
7✔
5253
      p_edge_identifier();
7✔
5254

5255
   vlog_node_t head = p_specify_terminal_descriptor();
7✔
5256

5257
   if (scan(tCOMMA, tTIMESGT) || peek_nth(2) == tTIMESGT)
7✔
5258
      (void)p_full_edge_sensitive_path_description(head);
5✔
5259
   else
5260
      (void)p_parallel_edge_sensitive_path_description(head);
2✔
5261

5262
   consume(tEQ);
7✔
5263

5264
   (void)p_path_delay_value();
7✔
5265

5266
   return NULL;
7✔
5267
}
5268

5269
static vlog_node_t p_state_dependent_path_declaration(void)
6✔
5270
{
5271
   // if ( module_path_expression ) simple_path_declaration
5272
   //   | if ( module_path_expression ) edge_sensitive_path_declaration
5273
   //   | ifnone simple_path_declaration
5274

5275
   BEGIN("state dependent path declaration");
12✔
5276

5277
   switch (one_of(tIF, tIFNONE)) {
6✔
5278
   case tIF:
4✔
5279
      consume(tLPAREN);
4✔
5280
      (void)p_module_path_expression();
4✔
5281
      consume(tRPAREN);
4✔
5282
      break;
4✔
5283
   case tIFNONE:
5284
      break;
5285
   }
5286

5287
   if (peek_nth(2) == tID)
6✔
5288
      (void)p_simple_path_declaration();
2✔
5289
   else {
5290
      // This is invalid for ifnone according to the grammar but is
5291
      // accepted by some simulators and seen in the wild
5292
      (void)p_edge_sensitive_path_declaration();
4✔
5293
   }
5294

5295
   return NULL;
6✔
5296
}
5297

5298
static vlog_node_t p_path_declaration(void)
18✔
5299
{
5300
   // simple_path_declaration ;
5301
   //  | edge_sensitive_path_declaration ;
5302
   //  | state_dependent_path_declaration ;
5303

5304
   BEGIN("path declaration");
36✔
5305

5306
   switch (peek()) {
18✔
5307
   case tIF:
6✔
5308
   case tIFNONE:
5309
      (void)p_state_dependent_path_declaration();
6✔
5310
      break;
6✔
5311
   case tLPAREN:
12✔
5312
      switch (peek_nth(2)) {
12✔
5313
      case tEDGE:
3✔
5314
      case tNEGEDGE:
5315
      case tPOSEDGE:
5316
         (void)p_edge_sensitive_path_declaration();
3✔
5317
         break;
3✔
5318
      default:
9✔
5319
         (void)p_simple_path_declaration();
9✔
5320
         break;
9✔
5321
      }
5322
      break;
UNCOV
5323
   default:
×
UNCOV
5324
      one_of(tIF, tIFNONE);
×
5325
   }
5326

5327
   consume(tSEMI);
18✔
5328
   return NULL;
18✔
5329
}
5330

5331
static void p_timing_check_event_control(void)
8✔
5332
{
5333
   // posedge | negedge | edge | edge_control_specifier
5334

5335
   BEGIN("timing check event control");
16✔
5336

5337
   one_of(tPOSEDGE, tNEGEDGE, tEDGE);
8✔
5338
}
8✔
5339

5340
static void p_scalar_timing_check_condition(void)
4✔
5341
{
5342
   //    expression
5343
   // | ~ expression
5344
   // | expression == scalar_constant
5345
   // | expression === scalar_constant
5346
   // | expression != scalar_constant
5347
   // | expression !== scalar_constant
5348

5349
   BEGIN("scalar timing check condition")
8✔
5350

5351
   p_expression();
4✔
5352
}
4✔
5353

5354
static void p_timing_check_condition(void)
4✔
5355
{
5356
   //     scalar_timing_check_condition
5357
   // | ( scalar_timing_check_condition )
5358

5359
   BEGIN("timing check condition");
8✔
5360

5361
   if (optional(tLPAREN)) {
4✔
5362
      p_scalar_timing_check_condition();
1✔
5363
      consume(tRPAREN);
1✔
5364
   }
5365
   else
5366
      p_scalar_timing_check_condition();
3✔
5367
}
4✔
5368

5369
static vlog_node_t p_timing_check_event(void)
20✔
5370
{
5371
   // [ timing_check_event_control ] specify_terminal_descriptor
5372
   //    [ &&& timing_check_condition ]
5373

5374
   BEGIN("timing check event");
40✔
5375

5376
   if (scan(tEDGE, tPOSEDGE, tNEGEDGE))
20✔
5377
      p_timing_check_event_control();
4✔
5378

5379
   (void)p_specify_terminal_descriptor();
20✔
5380

5381
   if (optional(tTRPLAMP))
20✔
5382
      p_timing_check_condition();
4✔
5383

5384
   return NULL;
20✔
5385
}
5386

5387
static vlog_node_t p_controlled_timing_check_event(void)
4✔
5388
{
5389
   // timing_check_event_control specify_terminal_descriptor
5390
   //    [ &&& timing_check_condition ]
5391

5392
   BEGIN("controlled timing check event");
8✔
5393

5394
   p_timing_check_event_control();
4✔
5395

5396
   (void)p_specify_terminal_descriptor();
4✔
5397

5398
   if (optional(tTRPLAMP))
4✔
UNCOV
5399
      p_timing_check_condition();
×
5400

5401
   return NULL;
4✔
5402
}
5403

5404
static vlog_node_t p_setup_or_hold_timing_check(void)
6✔
5405
{
5406
   // $setup ( data_event , reference_event , timing_check_limit
5407
   //   [ , [ notifier ] ] ) ;
5408
   //
5409
   // $hold ( reference_event , data_event , timing_check_limit
5410
   //   [ , [ notifier ] ] ) ;
5411

5412
   BEGIN("setup/hold timing check");
12✔
5413

5414
   one_of(tDLRSETUP, tDLRHOLD);
6✔
5415
   consume(tLPAREN);
6✔
5416

5417
   (void)p_timing_check_event();
6✔
5418

5419
   consume(tCOMMA);
6✔
5420

5421
   (void)p_timing_check_event();
6✔
5422

5423
   consume(tCOMMA);
6✔
5424

5425
   (void)p_expression();
6✔
5426

5427
   if (optional(tCOMMA)) {
6✔
5428
      if (peek() == tID)
4✔
5429
         p_identifier();
2✔
5430
   }
5431

5432
   consume(tRPAREN);
6✔
5433
   consume(tSEMI);
6✔
5434

5435
   return NULL;
6✔
5436
}
5437

5438
static vlog_node_t p_recovery_or_removal_timing_check(void)
2✔
5439
{
5440
   // $recovery ( reference_event , data_event , timing_check_limit
5441
   //   [ , [ notifier ] ] ) ;
5442
   //
5443
   // $removal ( reference_event , data_event , timing_check_limit
5444
   //   [ , [ notifier ] ] ) ;
5445

5446
   BEGIN("recovery/removal timing check");
4✔
5447

5448
   one_of(tDLRRECOVERY, tDLRREMOVAL);
2✔
5449
   consume(tLPAREN);
2✔
5450

5451
   (void)p_timing_check_event();
2✔
5452

5453
   consume(tCOMMA);
2✔
5454

5455
   (void)p_timing_check_event();
2✔
5456

5457
   consume(tCOMMA);
2✔
5458

5459
   (void)p_expression();
2✔
5460

5461
   if (optional(tCOMMA)) {
2✔
UNCOV
5462
      if (peek() == tID)
×
UNCOV
5463
         p_identifier();
×
5464
   }
5465

5466
   consume(tRPAREN);
2✔
5467
   consume(tSEMI);
2✔
5468

5469
   return NULL;
2✔
5470
}
5471

5472
static vlog_node_t p_width_timing_check(void)
1✔
5473
{
5474
   // $width ( controlled_reference_event , timing_check_limit , threshold
5475
   //   [ , [ notifier ] ] ) ;
5476

5477
   BEGIN("width timing check");
2✔
5478

5479
   consume(tDLRWIDTH);
1✔
5480
   consume(tLPAREN);
1✔
5481

5482
   (void)p_controlled_timing_check_event();
1✔
5483

5484
   consume(tCOMMA);
1✔
5485

5486
   (void)p_expression();
1✔
5487

5488
   consume(tCOMMA);
1✔
5489

5490
   (void)p_constant_expression();
1✔
5491

5492
   if (optional(tCOMMA)) {
1✔
UNCOV
5493
      if (peek() == tID)
×
UNCOV
5494
         p_identifier();
×
5495
   }
5496

5497
   consume(tRPAREN);
1✔
5498
   consume(tSEMI);
1✔
5499

5500
   return NULL;
1✔
5501
}
5502

5503
static vlog_node_t p_delayed_data_or_reference(void)
2✔
5504
{
5505
   // terminal_identifier
5506
   //   | terminal_identifier [ constant_mintypmax_expression ]
5507

5508
   BEGIN("delayed data/reference");
4✔
5509

5510
   p_identifier();
2✔
5511

5512
   return NULL;
2✔
5513
}
5514

5515
static vlog_node_t p_period_timing_check(void)
3✔
5516
{
5517
   // $period ( controlled_reference_event , timing_check_limit
5518
   //   [ , [ notifier ] ] ) ;
5519

5520
   BEGIN("period timing check");
6✔
5521

5522
   consume(tDLRPERIOD);
3✔
5523
   consume(tLPAREN);
3✔
5524

5525
   (void)p_controlled_timing_check_event();
3✔
5526

5527
   consume(tCOMMA);
3✔
5528

5529
   (void)p_expression();
3✔
5530

5531
   if (optional(tCOMMA)) {
3✔
5532
      if (peek() == tID)
2✔
5533
         p_identifier();
1✔
5534
   }
5535

5536
   consume(tRPAREN);
3✔
5537
   consume(tSEMI);
3✔
5538

5539
   return NULL;
3✔
5540
}
5541

5542
static vlog_node_t p_setuphold_or_recrem_timing_check(void)
2✔
5543
{
5544
   // $setuphold ( reference_event , data_event , timing_check_limit ,
5545
   //    timing_check_limit [ , [ notifier ] [ , [ timestamp_condition ]
5546
   //    [ , [ timecheck_condition ] [ , [ delayed_reference ]
5547
   //    [ , [ delayed_data ] ] ] ] ] ] ) ;
5548

5549
   BEGIN("setuphold/recrem timing check");
4✔
5550

5551
   one_of(tDLRSETUPHOLD, tDLRRECREM);
2✔
5552
   consume(tLPAREN);
2✔
5553

5554
   (void)p_timing_check_event();
2✔
5555

5556
   consume(tCOMMA);
2✔
5557

5558
   (void)p_timing_check_event();
2✔
5559

5560
   consume(tCOMMA);
2✔
5561

5562
   (void)p_expression();
2✔
5563

5564
   consume(tCOMMA);
2✔
5565

5566
   (void)p_expression();
2✔
5567

5568
   if (optional(tCOMMA)) {
2✔
5569
      if (peek() == tID)
2✔
5570
         p_identifier(); // notifier
2✔
5571

5572
      if (optional(tCOMMA)) {
2✔
5573
         if (not_at_token(tCOMMA, tRPAREN))
2✔
UNCOV
5574
            (void)p_mintypmax_expression();  // timestamp_condition
×
5575

5576
         if (optional(tCOMMA)) {
2✔
5577
            if (not_at_token(tCOMMA, tRPAREN))
2✔
UNCOV
5578
               (void)p_mintypmax_expression();  // timecheck_condition
×
5579

5580
            if (optional(tCOMMA)) {
2✔
5581
               if (not_at_token(tCOMMA, tRPAREN))
2✔
5582
                  p_delayed_data_or_reference();  // delayed_reference
1✔
5583

5584
               if (optional(tCOMMA)) {
2✔
5585
                  if (not_at_token(tCOMMA, tRPAREN))
2✔
5586
                     p_delayed_data_or_reference();  // delayed_data
1✔
5587
               }
5588
            }
5589
         }
5590
      }
5591
   }
5592

5593
   consume(tRPAREN);
2✔
5594
   consume(tSEMI);
2✔
5595

5596
   return NULL;
2✔
5597
}
5598

5599
static vlog_node_t p_system_timing_check(void)
14✔
5600
{
5601
   // $setup_timing_check | $hold_timing_check | $setuphold_timing_check
5602
   //   | $recovery_timing_check | $removal_timing_check | $recrem_timing_check
5603
   //   | $skew_timing_check | $timeskew_timing_check | $fullskew_timing_check
5604
   //   | $period_timing_check | $width_timing_check | $nochange_timing_check
5605

5606
   BEGIN("system timing check");
28✔
5607

5608
   switch (peek()) {
14✔
5609
   case tDLRSETUP:
6✔
5610
   case tDLRHOLD:
5611
      return p_setup_or_hold_timing_check();
6✔
5612
   case tDLRRECOVERY:
2✔
5613
   case tDLRREMOVAL:
5614
      return p_recovery_or_removal_timing_check();
2✔
5615
   case tDLRWIDTH:
1✔
5616
      return p_width_timing_check();
1✔
5617
   case tDLRPERIOD:
3✔
5618
      return p_period_timing_check();
3✔
5619
   case tDLRSETUPHOLD:
2✔
5620
   case tDLRRECREM:
5621
      return p_setuphold_or_recrem_timing_check();
2✔
UNCOV
5622
   default:
×
5623
      should_not_reach_here();
5624
   }
5625
}
5626

5627
static vlog_node_t p_pulse_control_specparam(void)
1✔
5628
{
5629
   // PATHPULSE$ = (reject_limit_value [, error_limit_value])
5630
   //   | PATHPULSE$specify_input_terminal_descriptor
5631
   //       $specify_output_terminal_descriptor =
5632
   //       (reject_limit_value [, error_limit_value])
5633

5634
   BEGIN("pulse control specparam");
2✔
5635

5636
   vlog_node_t v = vlog_new(V_SPECPARAM);
1✔
5637

5638
   consume(tPATHPULSE);
1✔
5639

5640
   consume(tEQ);
1✔
5641
   consume(tLPAREN);
1✔
5642

5643
   vlog_set_value(v, p_constant_mintypmax_expression());
1✔
5644

5645
   if (optional(tCOMMA))
1✔
5646
      (void)p_constant_mintypmax_expression();
1✔
5647

5648
   consume(tRPAREN);
1✔
5649

5650
   vlog_set_loc(v, CURRENT_LOC);
1✔
5651
   return v;
1✔
5652
}
5653

5654
static vlog_node_t p_specparam_assignment(void)
4✔
5655
{
5656
   // specparam_identifier = constant_mintypmax_expression
5657
   //   | pulse_control_specparam
5658

5659
   BEGIN("specparam assignment");
8✔
5660

5661
   if (peek() == tPATHPULSE)
4✔
5662
      return p_pulse_control_specparam();
1✔
5663
   else {
5664
      vlog_node_t v = vlog_new(V_SPECPARAM);
3✔
5665
      vlog_set_ident(v, p_identifier());
3✔
5666

5667
      consume(tEQ);
3✔
5668

5669
      vlog_set_value(v, p_constant_mintypmax_expression());
3✔
5670

5671
      vlog_set_loc(v, CURRENT_LOC);
3✔
5672
      vlog_symtab_put(symtab, v);
3✔
5673
      return v;
3✔
5674
   }
5675
}
5676

5677
static void p_list_of_specparam_assignments(vlog_node_t parent)
4✔
5678
{
5679
   // specparam_assignment { , specparam_assignment }
5680

5681
   BEGIN("list of specparam assignments");
8✔
5682

5683
   do {
4✔
5684
      vlog_add_decl(parent, p_specparam_assignment());
4✔
5685
   } while (optional(tCOMMA));
4✔
5686
}
4✔
5687

5688
static void p_specparam_declaration(vlog_node_t parent)
4✔
5689
{
5690
   // specparam [ packed_dimension ] list_of_specparam_assignments ;
5691

5692
   BEGIN("specparam declaration");
8✔
5693

5694
   consume(tSPECPARAM);
4✔
5695

5696
   if (peek() == tLSQUARE)
4✔
5697
      (void)p_packed_dimension();
1✔
5698

5699
   p_list_of_specparam_assignments(parent);
4✔
5700

5701
   consume(tSEMI);
4✔
5702
}
4✔
5703

5704
static void p_specify_item(vlog_node_t parent)
36✔
5705
{
5706
   // specparam_declaration | pulsestyle_declaration | showcancelled_declaration
5707
   //   | path_declaration | system_timing_check
5708

5709
   BEGIN("specify item");
72✔
5710

5711
   switch (peek()) {
36✔
5712
   case tSPECPARAM:
4✔
5713
      p_specparam_declaration(parent);
4✔
5714
      break;
4✔
5715
   case tLPAREN:
18✔
5716
   case tIF:
5717
   case tIFNONE:
5718
      (void)p_path_declaration();
18✔
5719
      break;
18✔
5720
   case tDLRSETUP:
14✔
5721
   case tDLRHOLD:
5722
   case tDLRRECOVERY:
5723
   case tDLRREMOVAL:
5724
   case tDLRSETUPHOLD:
5725
   case tDLRRECREM:
5726
   case tDLRWIDTH:
5727
   case tDLRPERIOD:
5728
      (void)p_system_timing_check();
14✔
5729
      break;
14✔
UNCOV
5730
   default:
×
UNCOV
5731
      one_of(tSPECPARAM, tLPAREN, tIF, tIFNONE, tDLRSETUP, tDLRHOLD,
×
5732
             tDLRRECOVERY, tDLRREMOVAL, tDLRSETUPHOLD, tDLRRECREM,
5733
             tDLRWIDTH, tDLRPERIOD);
5734
   }
5735
}
36✔
5736

5737
static vlog_node_t p_specify_block(void)
3✔
5738
{
5739
   // specify { specify_item } endspecify
5740

5741
   BEGIN("specify block");
6✔
5742

5743
   consume(tSPECIFY);
3✔
5744

5745
   vlog_node_t v = vlog_new(V_SPECIFY);
3✔
5746
   vlog_set_loc(v, CURRENT_LOC);
3✔
5747

5748
   vlog_symtab_push(symtab, v);
3✔
5749

5750
   while (not_at_token(tENDSPECIFY))
39✔
5751
      p_specify_item(v);
36✔
5752

5753
   vlog_symtab_pop(symtab);
3✔
5754

5755
   consume(tENDSPECIFY);
3✔
5756

5757
   vlog_set_loc(v, CURRENT_LOC);
3✔
5758
   return v;
3✔
5759
}
5760

5761
static vlog_node_t p_ordered_port_connection(void)
247✔
5762
{
5763
   // { attribute_instance } [ expression ]
5764

5765
   BEGIN("ordered port connection");
494✔
5766

5767
   optional_attributes();
247✔
5768

5769
   vlog_node_t v = vlog_new(V_PORT_CONN);
247✔
5770

5771
   if (not_at_token(tCOMMA, tRPAREN))
247✔
5772
      vlog_set_value(v, p_expression());
247✔
5773

5774
   vlog_set_loc(v, CURRENT_LOC);
247✔
5775
   return v;
247✔
5776
}
5777

5778
static vlog_node_t p_named_port_connection(void)
159✔
5779
{
5780
   // { attribute_instance } . port_identifier [ ( [ expression ] ) ]
5781
   //    | { attribute_instance } .*
5782

5783
   BEGIN("named port connection");
318✔
5784

5785
   optional_attributes();
159✔
5786

5787
   vlog_node_t v = vlog_new(V_PORT_CONN);
159✔
5788

5789
   consume(tDOT);
159✔
5790

5791
   vlog_set_ident(v, p_identifier());
159✔
5792

5793
   if (optional(tLPAREN)) {
159✔
5794

5795
      if (peek() != tRPAREN)
159✔
5796
         vlog_set_value(v, p_expression());
157✔
5797

5798
      consume(tRPAREN);
159✔
5799
   }
5800

5801
   vlog_set_loc(v, CURRENT_LOC);
159✔
5802
   return v;
159✔
5803
}
5804

5805
static void p_list_of_port_connections(vlog_node_t inst)
180✔
5806
{
5807
   // ordered_port_connection { , ordered_port_connection }
5808
   //   | named_port_connection { , named_port_connection }
5809

5810
   BEGIN("list of port connections");
360✔
5811

5812
   vlog_symtab_set_implicit(symtab, implicit_kind);
180✔
5813

5814
   do {
406✔
5815
      skip_over_attributes();
406✔
5816

5817
      if (peek() == tDOT)
406✔
5818
         vlog_add_param(inst, p_named_port_connection());
159✔
5819
      else
5820
         vlog_add_param(inst, p_ordered_port_connection());
247✔
5821
   } while (optional(tCOMMA));
406✔
5822

5823
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
180✔
5824
}
180✔
5825

5826
static vlog_node_t p_hierarchical_instance(void)
176✔
5827
{
5828
   // name_of_instance ( [ list_of_port_connections ] )
5829

5830
   BEGIN("hierarchical instance");
352✔
5831

5832
   vlog_node_t v = vlog_new(V_MOD_INST);
176✔
5833
   vlog_set_ident(v, p_identifier());
176✔
5834

5835
   consume(tLPAREN);
176✔
5836

5837
   if (peek() != tRPAREN)
176✔
5838
      p_list_of_port_connections(v);
163✔
5839

5840
   consume(tRPAREN);
176✔
5841

5842
   vlog_set_loc(v, CURRENT_LOC);
176✔
5843
   vlog_symtab_put(symtab, v);
176✔
5844
   return v;
176✔
5845
}
5846

5847
static vlog_node_t p_udp_instance(void)
17✔
5848
{
5849
   // [ name_of_instance ] ( output_terminal , input_terminal
5850
   //   { , input_terminal } )
5851

5852
   BEGIN("udp instance");
34✔
5853

5854
   vlog_node_t v = vlog_new(V_MOD_INST);
17✔
5855
   if (peek() == tID)
17✔
UNCOV
5856
      vlog_set_ident(v, p_identifier());
×
5857
   else
5858
      vlog_set_ident(v, ident_uniq("$unnamed"));
17✔
5859

5860
   consume(tLPAREN);
17✔
5861

5862
   p_list_of_port_connections(v);
17✔
5863

5864
   consume(tRPAREN);
17✔
5865

5866
   vlog_set_loc(v, CURRENT_LOC);
17✔
5867
   return v;
17✔
5868
}
5869

5870
static vlog_node_t p_param_expression(void)
66✔
5871
{
5872
   // mintypmax_expression | data_type | $
5873

5874
   BEGIN("param expression");
132✔
5875

5876
   return p_expression();   // TODO
66✔
5877
}
5878

5879
static vlog_node_t p_named_parameter_assignment(void)
18✔
5880
{
5881
   // . parameter_identifier ( [ param_expression ] )
5882

5883
   BEGIN("named parameter assignment");
36✔
5884

5885
   consume(tDOT);
18✔
5886

5887
   vlog_node_t v = vlog_new(V_PARAM_ASSIGN);
18✔
5888
   vlog_set_ident(v, p_identifier());
18✔
5889

5890
   consume(tLPAREN);
18✔
5891

5892
   if (peek() != tRPAREN)
18✔
5893
      vlog_set_value(v, p_param_expression());
14✔
5894

5895
   consume(tRPAREN);
18✔
5896

5897
   vlog_set_loc(v, CURRENT_LOC);
18✔
5898
   return v;
18✔
5899
}
5900

5901
static vlog_node_t p_ordered_parameter_assignment(void)
52✔
5902
{
5903
   // param_expression
5904

5905
   BEGIN("ordered parameter assignment");
104✔
5906

5907
   vlog_node_t v = vlog_new(V_PARAM_ASSIGN);
52✔
5908
   vlog_set_value(v, p_param_expression());
52✔
5909

5910
   vlog_set_loc(v, CURRENT_LOC);
52✔
5911
   return v;
52✔
5912
}
5913

5914
static void p_list_of_parameter_assignments(vlog_node_t inst)
60✔
5915
{
5916
   // ordered_parameter_assignment { , ordered_parameter_assignment }
5917
   //   | named_parameter_assignment { , named_parameter_assignment }
5918

5919
   BEGIN("list of parameter assignments");
120✔
5920

5921
   do {
70✔
5922
      if (peek() == tDOT)
70✔
5923
         vlog_add_param(inst, p_named_parameter_assignment());
18✔
5924
      else
5925
         vlog_add_param(inst, p_ordered_parameter_assignment());
52✔
5926
   } while (optional(tCOMMA));
70✔
5927
}
60✔
5928

5929
static void p_parameter_value_assignment(vlog_node_t inst)
60✔
5930
{
5931
   // # ( [ list_of_parameter_assignments ] )
5932

5933
   BEGIN("parameter value assignment");
120✔
5934

5935
   consume(tHASH);
60✔
5936
   consume(tLPAREN);
60✔
5937

5938
   if (peek() != tRPAREN)
60✔
5939
      p_list_of_parameter_assignments(inst);
60✔
5940

5941
   consume(tRPAREN);
60✔
5942
}
60✔
5943

5944
static void p_module_or_udp_instantiation(vlog_node_t mod)
187✔
5945
{
5946
   // module_identifier [ parameter_value_assignment ] hierarchical_instance
5947
   //   { , hierarchical_instance } ;
5948
   //
5949
   // udp_identifier [ drive_strength ] [ delay2 ] udp_instance
5950
   //   { , udp_instance } ;
5951

5952
   BEGIN("module instantiation");
374✔
5953

5954
   vlog_node_t v = vlog_new(V_INST_LIST);
187✔
5955
   vlog_set_ident(v, p_identifier());
187✔
5956

5957
   if (peek() == tHASH)
187✔
5958
      p_parameter_value_assignment(v);
60✔
5959

5960
   do {
193✔
5961
      if (peek() == tLPAREN)
193✔
5962
         vlog_add_stmt(v, p_udp_instance());
17✔
5963
      else
5964
         vlog_add_stmt(v, p_hierarchical_instance());
176✔
5965
   } while (optional(tCOMMA));
193✔
5966

5967
   consume(tSEMI);
187✔
5968

5969
   vlog_set_loc(v, CURRENT_LOC);
187✔
5970

5971
   vlog_add_stmt(mod, v);
187✔
5972
}
187✔
5973

5974
static vlog_node_t p_defparam_assignment(void)
3✔
5975
{
5976
   // hierarchical_parameter_identifier = constant_mintypmax_expression
5977

5978
   BEGIN("defparam assignment");
6✔
5979

5980
   vlog_node_t v = vlog_new(V_DEFPARAM);
3✔
5981
   vlog_set_target(v, p_hierarchical_identifier(NULL));
3✔
5982

5983
   consume(tEQ);
3✔
5984

5985
   vlog_set_value(v, p_constant_mintypmax_expression());
3✔
5986

5987
   vlog_set_loc(v, CURRENT_LOC);
3✔
5988
   return v;
3✔
5989
}
5990

5991
static void p_list_of_defparam_assignments(vlog_node_t parent)
3✔
5992
{
5993
   // defparam_assignment { , defparam_assignment }
5994

5995
   BEGIN("list of defparam assignments");
6✔
5996

5997
   do {
3✔
5998
      vlog_add_stmt(parent, p_defparam_assignment());
3✔
5999
   } while (optional(tCOMMA));
3✔
6000
}
3✔
6001

6002
static void p_parameter_override(vlog_node_t parent)
3✔
6003
{
6004
   // defparam list_of_defparam_assignments ;
6005

6006
   BEGIN("parameter override");
6✔
6007

6008
   consume(tDEFPARAM);
3✔
6009

6010
   p_list_of_defparam_assignments(parent);
3✔
6011

6012
   consume(tSEMI);
3✔
6013
}
3✔
6014

6015
static void p_module_or_generate_item(vlog_node_t mod)
6,789✔
6016
{
6017
   // { attribute_instance } parameter_override
6018
   //   | { attribute_instance } gate_instantiation
6019
   //   | { attribute_instance } udp_instantiation
6020
   //   | { attribute_instance } module_instantiation
6021
   //   | { attribute_instance } module_common_item
6022

6023
   BEGIN("module or generate item");
13,578✔
6024

6025
   optional_attributes();
6,789✔
6026

6027
   switch (peek()) {
6,789✔
6028
   case tALWAYS:
6,507✔
6029
   case tALWAYSCOMB:
6030
   case tALWAYSFF:
6031
   case tALWAYSLATCH:
6032
   case tWIRE:
6033
   case tUWIRE:
6034
   case tSUPPLY0:
6035
   case tSUPPLY1:
6036
   case tTRI:
6037
   case tTRI0:
6038
   case tTRI1:
6039
   case tTRIAND:
6040
   case tTRIOR:
6041
   case tTRIREG:
6042
   case tWAND:
6043
   case tWOR:
6044
   case tINTERCONNECT:
6045
   case tREG:
6046
   case tSTRUCT:
6047
   case tUNION:
6048
   case tASSIGN:
6049
   case tINITIAL:
6050
   case tTYPEDEF:
6051
   case tENUM:
6052
   case tSVINT:
6053
   case tINTEGER:
6054
   case tSVREAL:
6055
   case tSHORTREAL:
6056
   case tREALTIME:
6057
   case tTIME:
6058
   case tTASK:
6059
   case tFUNCTION:
6060
   case tLOCALPARAM:
6061
   case tPARAMETER:
6062
   case tIF:
6063
   case tCASE:
6064
   case tFOR:
6065
   case tEVENT:
6066
   case tGENVAR:
6067
   case tVAR:
6068
   case tLOGIC:
6069
   case tBIT:
6070
   case tSHORTINT:
6071
   case tLONGINT:
6072
   case tBYTE:
6073
   case tSTRINGK:
6074
   case tIMPORT:
6075
      p_module_common_item(mod);
6,507✔
6076
      break;
6,507✔
6077
   case tPULLDOWN:
68✔
6078
   case tPULLUP:
6079
   case tAND:
6080
   case tNAND:
6081
   case tOR:
6082
   case tNOR:
6083
   case tXOR:
6084
   case tXNOR:
6085
   case tNOT:
6086
   case tBUF:
6087
   case tBUFIF0:
6088
   case tBUFIF1:
6089
   case tNOTIF0:
6090
   case tNOTIF1:
6091
   case tTRAN:
6092
   case tTRANIF0:
6093
   case tTRANIF1:
6094
   case tRTRAN:
6095
   case tRTRANIF0:
6096
   case tRTRANIF1:
6097
      p_gate_instantiation(mod);
68✔
6098
      break;
68✔
6099
   case tDEFPARAM:
3✔
6100
      p_parameter_override(mod);
3✔
6101
      break;
3✔
6102
   case tID:
211✔
6103
      {
6104
         vlog_node_t ref = peek_reference();
211✔
6105
         if (ref == NULL)
211✔
6106
            p_module_or_udp_instantiation(mod);
187✔
6107
         else
6108
            p_module_common_item(mod);
24✔
6109
      }
6110
      break;
UNCOV
6111
   default:
×
UNCOV
6112
      expect(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
×
6113
             tSUPPLY0, tSUPPLY1, tTRI,  tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
6114
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tASSIGN,
6115
             tINITIAL, tTYPEDEF, tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL,
6116
             tREALTIME, tTIME, tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER, tIF,
6117
             tFOR, tEVENT, tGENVAR, tVAR, tLOGIC, tBIT, tSHORTINT, tLONGINT,
6118
             tBYTE, tSTRINGK, tIMPORT, tPULLDOWN, tPULLUP, tID, tAND, tNAND,
6119
             tOR, tNOR, tXOR, tXNOR, tNOT, tBUF, tBUFIF0, tBUFIF1, tNOTIF0,
6120
             tNOTIF1, tDEFPARAM, tID);
UNCOV
6121
      drop_tokens_until(&state, tSEMI);
×
6122
   }
6123
}
6,789✔
6124

6125
static void p_generate_region(vlog_node_t mod)
20✔
6126
{
6127
   // generate { generate_item } endgenerate
6128

6129
   BEGIN("generate region");
40✔
6130

6131
   // Has no real meaning in System Verilog
6132

6133
   // TODO: generate regions do not nest so check mod is V_MODULE
6134

6135
   consume(tGENERATE);
20✔
6136

6137
   if (optional(tBEGIN)) {
20✔
6138
      // This is non-standard but seen in some legacy code
6139
      consume(tCOLON);
1✔
6140

6141
      vlog_node_t b = vlog_new(V_BLOCK);
1✔
6142
      vlog_set_ident(b, p_identifier());
1✔
6143

6144
      while (not_at_token(tEND))
1✔
UNCOV
6145
         p_generate_item(b);
×
6146

6147
      consume(tEND);
1✔
6148

6149
      vlog_set_loc(b, CURRENT_LOC);
1✔
6150
      vlog_add_stmt(mod, b);
1✔
6151
   }
6152
   else {
6153
      while (not_at_token(tENDGENERATE))
38✔
6154
         p_generate_item(mod);
19✔
6155
   }
6156

6157
   consume(tENDGENERATE);
20✔
6158
}
20✔
6159

6160
static void p_non_port_module_item(vlog_node_t mod)
6,680✔
6161
{
6162
   // generate_region | module_or_generate_item | specify_block
6163
   //   | { attribute_instance } specparam_declaration | program_declaration
6164
   //   | module_declaration | interface_declaration | timeunits_declaration
6165

6166
   BEGIN("non-port module item");
13,360✔
6167

6168
   switch (peek()) {
6,680✔
6169
   case tALWAYS:
6,655✔
6170
   case tALWAYSCOMB:
6171
   case tALWAYSFF:
6172
   case tALWAYSLATCH:
6173
   case tWIRE:
6174
   case tUWIRE:
6175
   case tSUPPLY0:
6176
   case tSUPPLY1:
6177
   case tTRI:
6178
   case tTRI0:
6179
   case tTRI1:
6180
   case tTRIAND:
6181
   case tTRIOR:
6182
   case tTRIREG:
6183
   case tWAND:
6184
   case tWOR:
6185
   case tINTERCONNECT:
6186
   case tREG:
6187
   case tSTRUCT:
6188
   case tUNION:
6189
   case tASSIGN:
6190
   case tINITIAL:
6191
   case tPULLDOWN:
6192
   case tPULLUP:
6193
   case tID:
6194
   case tATTRBEGIN:
6195
   case tAND:
6196
   case tNAND:
6197
   case tOR:
6198
   case tNOR:
6199
   case tXOR:
6200
   case tXNOR:
6201
   case tNOT:
6202
   case tBUF:
6203
   case tBUFIF0:
6204
   case tBUFIF1:
6205
   case tNOTIF0:
6206
   case tNOTIF1:
6207
   case tTRAN:
6208
   case tTRANIF0:
6209
   case tTRANIF1:
6210
   case tRTRAN:
6211
   case tRTRANIF0:
6212
   case tRTRANIF1:
6213
   case tTYPEDEF:
6214
   case tENUM:
6215
   case tSVINT:
6216
   case tINTEGER:
6217
   case tSVREAL:
6218
   case tSHORTREAL:
6219
   case tREALTIME:
6220
   case tTIME:
6221
   case tTASK:
6222
   case tFUNCTION:
6223
   case tLOCALPARAM:
6224
   case tPARAMETER:
6225
   case tEVENT:
6226
   case tIF:
6227
   case tFOR:
6228
   case tGENVAR:
6229
   case tVAR:
6230
   case tLOGIC:
6231
   case tBIT:
6232
   case tSHORTINT:
6233
   case tLONGINT:
6234
   case tBYTE:
6235
   case tSTRINGK:
6236
   case tIMPORT:
6237
   case tDEFPARAM:
6238
      p_module_or_generate_item(mod);
6,655✔
6239
      break;
6,655✔
6240
   case tSPECIFY:
3✔
6241
      vlog_add_stmt(mod, p_specify_block());
3✔
6242
      break;
3✔
6243
   case tGENERATE:
20✔
6244
      p_generate_region(mod);
20✔
6245
      break;
20✔
6246
   default:
2✔
6247
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
2✔
6248
             tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
6249
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tASSIGN,
6250
             tPULLDOWN, tPULLUP, tID, tATTRBEGIN, tAND, tNAND, tOR, tNOR, tXOR,
6251
             tXNOR, tNOT, tBUF, tBUFIF0, tBUFIF1, tNOTIF0, tNOTIF1, tTYPEDEF,
6252
             tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTIME,
6253
             tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER, tEVENT, tIF, tFOR,
6254
             tGENVAR, tVAR, tLOGIC, tBIT, tSHORTINT, tLONGINT, tBYTE, tSTRINGK,
6255
             tIMPORT, tDEFPARAM, tSPECIFY, tGENERATE);
6256
      drop_tokens_until(&state, tSEMI);
2✔
6257
   }
6258
}
6,680✔
6259

6260
static void p_module_item(vlog_node_t mod)
7,112✔
6261
{
6262
   // port_declaration ; | non_port_module_item
6263

6264
   BEGIN("module item");
14,224✔
6265

6266
   skip_over_attributes();
7,112✔
6267

6268
   if (scan(tINOUT, tINPUT, tOUTPUT)) {
7,112✔
6269
      p_port_declaration(mod);
432✔
6270
      consume(tSEMI);
432✔
6271
   }
6272
   else
6273
      p_non_port_module_item(mod);
6,680✔
6274
}
7,112✔
6275

6276
static void p_ansi_port_declaration(vlog_node_t mod, v_port_kind_t *kind,
155✔
6277
                                    vlog_node_t *dt)
6278
{
6279
   // [ net_port_header | interface_port_header ] port_identifier
6280
   //     { unpacked_dimension } [ = constant_expression ]
6281
   // | [ variable_port_header ] port_identifier { variable_dimension }
6282
   //     [ = constant_expression ]
6283
   // | [ port_direction ] . port_identifier ( [ expression ] )
6284

6285
   BEGIN("ANSI port declaration");
310✔
6286

6287
   if (peek() != tID)
155✔
6288
      p_net_port_header(kind, dt);
133✔
6289
   else if (*dt == NULL)
22✔
UNCOV
6290
      *dt = implicit_type();
×
6291

6292
   ident_t id, ext;
155✔
6293
   p_external_identifier(&id, &ext);
155✔
6294

6295
   vlog_node_t v = vlog_new(V_PORT_DECL);
155✔
6296
   vlog_set_subkind(v, *kind);
155✔
6297
   vlog_set_ident(v, id);
155✔
6298
   vlog_set_ident2(v, ext);
155✔
6299
   vlog_set_type(v, *dt);
155✔
6300
   vlog_set_loc(v, &state.last_loc);
155✔
6301

6302
   if (optional(tEQ))
155✔
6303
      vlog_set_value(v, p_constant_expression());
9✔
6304

6305
   vlog_add_decl(mod, v);
155✔
6306
   vlog_symtab_put(symtab, v);
155✔
6307

6308
   vlog_node_t ref = vlog_new(V_REF);
155✔
6309
   vlog_set_loc(ref, CURRENT_LOC);
155✔
6310
   vlog_set_ident(ref, id);
155✔
6311
   vlog_set_ref(ref, v);
155✔
6312

6313
   vlog_add_port(mod, ref);
155✔
6314
}
155✔
6315

6316
static void p_list_of_port_declarations(vlog_node_t mod)
134✔
6317
{
6318
   // ( [ { attribute_instance } ansi_port_declaration
6319
   //   { , { attribute_instance } ansi_port_declaration } ] )
6320

6321
   BEGIN("list of port declarations");
268✔
6322

6323
   consume(tLPAREN);
134✔
6324

6325
   if (peek() != tRPAREN) {
134✔
6326
      v_port_kind_t kind = V_PORT_INPUT;
62✔
6327
      vlog_node_t dt = NULL;
62✔
6328
      do {
155✔
6329
         optional_attributes();
155✔
6330
         p_ansi_port_declaration(mod, &kind, &dt);
155✔
6331
      } while (optional(tCOMMA));
155✔
6332
   }
6333

6334
   consume(tRPAREN);
134✔
6335
}
134✔
6336

6337
static void p_parameter_port_declaration(vlog_node_t mod)
53✔
6338
{
6339
   // parameter_declaration
6340
   //    | local_parameter_declaration
6341
   //    | data_type list_of_param_assignments
6342
   //    | type list_of_type_assignments
6343

6344
   BEGIN("parameter port declaration");
106✔
6345

6346
   switch (peek()) {
53✔
6347
   case tPARAMETER:
47✔
6348
      p_parameter_declaration(mod);
47✔
6349
      break;
47✔
6350
   case tLOCALPARAM:
5✔
6351
      p_local_parameter_declaration(mod);
5✔
6352
      break;
5✔
6353
   default:
1✔
6354
      // TODO: Add parsing of "type" declarations example #(type T = bit)
6355
      {
6356
         vlog_node_t datatype = p_data_type();
1✔
6357
         p_list_of_param_assignments(mod, datatype, V_PARAM_DECL);
1✔
6358
      }
6359
      break;
1✔
6360
   }
6361
}
53✔
6362

6363
static void p_parameter_port_list(vlog_node_t mod)
27✔
6364
{
6365
   // # ( list_of_param_assignments { , parameter_port_declaration } )
6366
   //    | # ( parameter_port_declaration { , parameter_port_declaration } )
6367
   //    | # ( )
6368

6369
   BEGIN("parameter port list");
54✔
6370

6371
   consume(tHASH);
27✔
6372
   consume(tLPAREN);
27✔
6373

6374
   if (peek() != tRPAREN) {
27✔
6375
      do {
54✔
6376
         if (peek() == tID)
54✔
6377
            p_list_of_param_assignments(mod, implicit_type(), V_PARAM_DECL);
1✔
6378
         else
6379
            p_parameter_port_declaration(mod);
53✔
6380
      } while(optional(tCOMMA));
54✔
6381
   }
6382

6383
   consume(tRPAREN);
27✔
6384
}
27✔
6385

6386
static void p_module_ansi_header(vlog_node_t mod)
747✔
6387
{
6388
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
6389
   //    { package_import_declaration } [ parameter_port_list ]
6390
   ///   [ list_of_port_declarations ] ;
6391

6392
   EXTEND("module ANSI header");
1,494✔
6393

6394
   if (peek() == tLPAREN)
747✔
6395
      p_list_of_port_declarations(mod);
134✔
6396

6397
   consume(tSEMI);
747✔
6398

6399
   vlog_set_loc(mod, CURRENT_LOC);
747✔
6400
}
747✔
6401

6402
static vlog_node_t p_port_reference(void)
458✔
6403
{
6404
   // port_identifier constant_select
6405

6406
   BEGIN("port reference");
916✔
6407

6408
   vlog_node_t v = vlog_new(V_REF);
458✔
6409
   vlog_set_ident(v, p_identifier());
458✔
6410
   vlog_set_loc(v, CURRENT_LOC);
458✔
6411
   return v;
458✔
6412
}
6413

6414
static vlog_node_t p_port_expression(void)
458✔
6415
{
6416
   // port_reference | { port_reference { , port_reference } }
6417

6418
   BEGIN("port expression");
916✔
6419

6420
   return p_port_reference();
458✔
6421
}
6422

6423
static vlog_node_t p_port(void)
458✔
6424
{
6425
   // [ port_expression ] | . port_identifier ( [ port_expression ] )
6426

6427
   BEGIN("port");
916✔
6428

6429
   return p_port_expression();
458✔
6430
}
6431

6432
static void p_list_of_ports(vlog_node_t mod)
152✔
6433
{
6434
   // ( port { , port } )
6435

6436
   BEGIN("list of ports");
304✔
6437

6438
   consume(tLPAREN);
152✔
6439

6440
   do {
458✔
6441
      vlog_add_port(mod, p_port());
458✔
6442
   } while (optional(tCOMMA));
458✔
6443

6444
   consume(tRPAREN);
152✔
6445
}
152✔
6446

6447
static void p_module_nonansi_header(vlog_node_t mod)
152✔
6448
{
6449
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
6450
   //    { package_import_declaration } [ parameter_port_list ] list_of_ports ;
6451

6452
   EXTEND("module non-ANSI header");
304✔
6453

6454
   p_list_of_ports(mod);
152✔
6455

6456
   consume(tSEMI);
152✔
6457

6458
   vlog_set_loc(mod, CURRENT_LOC);
152✔
6459
}
152✔
6460

6461
static vlog_node_t p_module_declaration(void)
899✔
6462
{
6463
   // module_nonansi_header [ timeunits_declaration ] { module_item }
6464
   //      endmodule [ : module_identifier ]
6465
   //   | module_ansi_header [ timeunits_declaration ] { non_port_module_item }
6466
   //      endmodule [ : module_identifier ]
6467
   //   | { attribute_instance } module_keyword [ lifetime ] module_identifier
6468
   //      ( .* ) ; [ timeunits_declaration ] { module_item } endmodule
6469
   //      [ : module_identifier ]
6470
   //   | extern module_nonansi_header
6471
   //   | extern module_ansi_header
6472

6473
   BEGIN("module declaration");
1,798✔
6474

6475
   vlog_node_t mod = vlog_new(V_MODULE);
899✔
6476

6477
   optional_attributes();
899✔
6478

6479
   consume(tMODULE);
899✔
6480

6481
   ident_t id, ext;
899✔
6482
   p_external_identifier(&id, &ext);
899✔
6483
   vlog_set_ident2(mod, id);
899✔
6484

6485
   vlog_set_loc(mod, &state.last_loc);
899✔
6486

6487
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
899✔
6488
   vlog_set_ident(mod, qual);
899✔
6489

6490
   vlog_symtab_push(symtab, mod);
899✔
6491

6492
   while (peek() == tIMPORT)
899✔
UNCOV
6493
      p_package_import_declaration(mod);
×
6494

6495
   if (peek() == tHASH) {
899✔
6496
      p_parameter_port_list(mod);
27✔
6497
      param_kind = V_LOCALPARAM;
27✔
6498
   }
6499

6500
   if (peek() == tLPAREN && peek_nth(2) == tID)
899✔
6501
      p_module_nonansi_header(mod);
152✔
6502
   else
6503
      p_module_ansi_header(mod);
747✔
6504

6505
   while (not_at_token(tENDMODULE))
8,011✔
6506
      p_module_item(mod);
7,112✔
6507

6508
   consume(tENDMODULE);
899✔
6509

6510
   if (optional(tCOLON)) {
899✔
6511
      ident_t name = p_identifier();
2✔
6512
      if (id != name)
2✔
6513
         error_at(&state.last_loc, "'%s' does not match module name '%s'",
1✔
6514
                  istr(name), istr(id));
6515
   }
6516

6517
   vlog_symtab_pop(symtab);
899✔
6518
   return mod;
899✔
6519
}
6520

6521
static void p_udp_port_list(vlog_node_t udp)
26✔
6522
{
6523
   // output_port_identifier , input_port_identifier { , input_port_identifier }
6524

6525
   BEGIN("UDP port list");
52✔
6526

6527
   vlog_node_t oref = vlog_new(V_REF);
26✔
6528
   vlog_set_ident(oref, p_identifier());
26✔
6529
   vlog_set_loc(oref, &state.last_loc);
26✔
6530

6531
   vlog_add_port(udp, oref);
26✔
6532

6533
   consume(tCOMMA);
26✔
6534

6535
   vlog_node_t iref = vlog_new(V_REF);
26✔
6536
   vlog_set_ident(iref, p_identifier());
26✔
6537
   vlog_set_loc(iref, &state.last_loc);
26✔
6538

6539
   vlog_add_port(udp, iref);
26✔
6540

6541
   while (optional(tCOMMA)) {
54✔
6542
      vlog_node_t iref = vlog_new(V_REF);
28✔
6543
      vlog_set_ident(iref, p_identifier());
28✔
6544
      vlog_set_loc(iref, &state.last_loc);
28✔
6545

6546
      vlog_add_port(udp, iref);
28✔
6547
   }
6548
}
26✔
6549

6550
static vlog_node_t p_udp_nonansi_declaration(void)
26✔
6551
{
6552
   // { attribute_instance } primitive udp_identifier ( udp_port_list ) ;
6553

6554
   BEGIN("UDP non-ANSI declaration");
52✔
6555

6556
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
26✔
6557

6558
   consume(tPRIMITIVE);
26✔
6559

6560
   ident_t id, ext;
26✔
6561
   p_external_identifier(&id, &ext);
26✔
6562
   vlog_set_ident2(udp, id);
26✔
6563

6564
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
26✔
6565
   vlog_set_ident(udp, qual);
26✔
6566

6567
   consume(tLPAREN);
26✔
6568

6569
   p_udp_port_list(udp);
26✔
6570

6571
   consume(tRPAREN);
26✔
6572
   consume(tSEMI);
26✔
6573

6574
   vlog_set_loc(udp, CURRENT_LOC);
26✔
6575
   return udp;
26✔
6576
}
6577

6578
static void p_list_of_udp_port_identifiers(vlog_node_t udp, v_port_kind_t kind)
27✔
6579
{
6580
   // port_identifier { , port_identifier }
6581

6582
   BEGIN("list of UDP port identifiers");
54✔
6583

6584
   do {
54✔
6585
      ident_t id, ext;
54✔
6586
      p_external_identifier(&id, &ext);
54✔
6587

6588
      vlog_node_t p = vlog_new(V_PORT_DECL);
54✔
6589
      vlog_set_subkind(p, kind);
54✔
6590
      vlog_set_ident(p, id);
54✔
6591
      vlog_set_ident2(p, ext);
54✔
6592
      vlog_set_type(p, implicit_type());
54✔
6593
      vlog_set_loc(p, &state.last_loc);
54✔
6594

6595
      vlog_add_decl(udp, p);
54✔
6596
      vlog_symtab_put(symtab, p);
54✔
6597
   } while (optional(tCOMMA));
54✔
6598
}
27✔
6599

6600
static void p_udp_output_declaration(vlog_node_t udp, bool *has_reg)
27✔
6601
{
6602
   // { attribute_instance } output port_identifier
6603
   //    | { attribute_instance } output reg port_identifier
6604
   //         [ = constant_expression ]
6605

6606
   BEGIN("UDP output declaration");
54✔
6607

6608
   consume(tOUTPUT);
27✔
6609

6610
   const bool isreg = optional(tREG);
27✔
6611

6612
   ident_t id, ext;
27✔
6613
   p_external_identifier(&id, &ext);
27✔
6614

6615
   vlog_node_t v = vlog_new(V_PORT_DECL);
27✔
6616
   vlog_set_subkind(v, V_PORT_OUTPUT);
27✔
6617
   vlog_set_ident(v, id);
27✔
6618
   vlog_set_ident2(v, ext);
27✔
6619
   vlog_set_loc(v, &state.last_loc);
27✔
6620

6621
   if (isreg) {
27✔
6622
      vlog_set_type(v, logic_type());
2✔
6623
      *has_reg = true;
2✔
6624
   }
6625
   else
6626
      vlog_set_type(v, implicit_type());
25✔
6627

6628
   vlog_add_decl(udp, v);
27✔
6629
   vlog_symtab_put(symtab, v);
27✔
6630
}
27✔
6631

6632
static void p_udp_input_declaration(vlog_node_t udp)
27✔
6633
{
6634
   // { attribute_instance } input list_of_udp_port_identifiers
6635

6636
   BEGIN("UDP input declaration");
54✔
6637

6638
   consume(tINPUT);
27✔
6639

6640
   p_list_of_udp_port_identifiers(udp, V_PORT_INPUT);
27✔
6641
}
27✔
6642

6643
static vlog_node_t p_udp_reg_declaration(void)
13✔
6644
{
6645
   // { attribute_instance } reg variable_identifier
6646

6647
   BEGIN("UDP reg declaration");
26✔
6648

6649
   consume(tREG);
13✔
6650

6651
   ident_t id = p_identifier();
13✔
6652

6653
   vlog_node_t reg = vlog_new(V_VAR_DECL);
13✔
6654
   vlog_set_loc(reg, &state.last_loc);
13✔
6655
   vlog_set_ident(reg, id);
13✔
6656
   vlog_set_type(reg, logic_type());
13✔
6657

6658
   return reg;
13✔
6659
}
6660

6661
static void p_udp_port_declaration(vlog_node_t udp, bool *has_reg)
65✔
6662
{
6663
   // udp_output_declaration ; | udp_input_declaration ; | udp_reg_declaration ;
6664

6665
   BEGIN("UDP port declaration");
130✔
6666

6667
   switch (peek()) {
65✔
6668
   case tOUTPUT:
26✔
6669
      p_udp_output_declaration(udp, has_reg);
26✔
6670
      break;
26✔
6671
   case tINPUT:
26✔
6672
      p_udp_input_declaration(udp);
26✔
6673
      break;
26✔
6674
   case tREG:
13✔
6675
      {
6676
         vlog_node_t v = p_udp_reg_declaration();
13✔
6677
         vlog_add_decl(udp, v);
13✔
6678
         vlog_symtab_put(symtab, v);
13✔
6679
         *has_reg = true;
13✔
6680
      }
6681
      break;
13✔
6682
   default:
×
UNCOV
6683
      one_of(tOUTPUT, tINPUT, tREG);
×
UNCOV
6684
      break;
×
6685
   }
6686

6687
   consume(tSEMI);
65✔
6688
}
65✔
6689

6690
static void p_udp_declaration_port_list(vlog_node_t udp, bool *has_reg)
1✔
6691
{
6692
   // udp_output_declaration , udp_input_declaration { , udp_input_declaration }
6693

6694
   BEGIN("UDP declaration port list");
2✔
6695

6696
   p_udp_output_declaration(udp, has_reg);
1✔
6697

6698
   consume(tCOMMA);
1✔
6699

6700
   do {
1✔
6701
      p_udp_input_declaration(udp);
1✔
6702
   } while (optional(tCOMMA));
1✔
6703

6704
   const int ndecls = vlog_decls(udp);
1✔
6705
   for (int i = 0; i < ndecls; i++) {
3✔
6706
      vlog_node_t p = vlog_decl(udp, i);
2✔
6707
      if (vlog_kind(p) != V_PORT_DECL)
2✔
UNCOV
6708
         continue;
×
6709

6710
      vlog_node_t ref = vlog_new(V_REF);
2✔
6711
      vlog_set_loc(ref, vlog_loc(p));
2✔
6712
      vlog_set_ident(ref, vlog_ident(p));
2✔
6713
      vlog_set_ref(ref, p);
2✔
6714

6715
      vlog_add_port(udp, ref);
2✔
6716
   }
6717
}
1✔
6718

6719
static vlog_node_t p_output_symbol(void)
105✔
6720
{
6721
   // 0 | 1 | x | X
6722

6723
   BEGIN("output symbol");
210✔
6724

6725
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
105✔
6726
   vlog_set_subkind(v, V_UDP_SYMBOL_OUTPUT);
105✔
6727

6728
   if (consume(tUDPLEVEL)) {
105✔
6729
      switch (state.last_lval.i64) {
105✔
6730
      case '0':
105✔
6731
      case '1':
6732
      case 'x':
6733
      case 'X':
6734
         vlog_set_ival(v, state.last_lval.i64);
105✔
6735
         break;
105✔
UNCOV
6736
      default:
×
UNCOV
6737
         parse_error(&state.last_loc, "'%c' is not a valid output symbol",
×
6738
                     (char)state.last_lval.i64);
6739
         break;
6740
      }
6741
   }
6742

6743
   vlog_set_loc(v, CURRENT_LOC);
105✔
6744
   return v;
105✔
6745
}
6746

6747
static vlog_node_t p_level_symbol(void)
437✔
6748
{
6749
   // 0 | 1 | x | X | ? | b | B
6750

6751
   BEGIN("level symbol");
874✔
6752

6753
   consume(tUDPLEVEL);
437✔
6754

6755
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
437✔
6756
   vlog_set_subkind(v, V_UDP_SYMBOL_INPUT);
437✔
6757
   vlog_set_ival(v, state.last_lval.i64);
437✔
6758

6759
   vlog_set_loc(v, CURRENT_LOC);
437✔
6760
   return v;
437✔
6761
}
6762

6763
static vlog_node_t p_next_state(void)
101✔
6764
{
6765
   // output_symbol | -
6766

6767
   BEGIN("next state");
202✔
6768

6769
   switch (peek()) {
101✔
6770
   case tMINUS:
35✔
6771
      consume(tMINUS);
35✔
6772
      break;
35✔
6773
   case tUDPLEVEL:
66✔
6774
      return p_output_symbol();
66✔
UNCOV
6775
   default:
×
UNCOV
6776
      one_of(tUDPLEVEL, tMINUS);
×
6777
   }
6778

6779
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
35✔
6780
   vlog_set_subkind(v, V_UDP_SYMBOL_OUTPUT);
35✔
6781
   vlog_set_ival(v, '-');
35✔
6782

6783
   vlog_set_loc(v, CURRENT_LOC);
35✔
6784
   return v;
35✔
6785
}
6786

6787
static vlog_node_t p_edge_symbol(void)
28✔
6788
{
6789
   // r | R | f | F | p | P | n | N | *
6790

6791
   BEGIN("edge symbol");
56✔
6792

6793
   consume(tUDPEDGE);
28✔
6794

6795
   char left, right;
28✔
6796
   switch (state.last_lval.i64) {
28✔
6797
   case 'r': case 'R': left = '0'; right = '1'; break;
UNCOV
6798
   case 'f': case 'F': left = '1'; right = '0'; break;
×
6799
   case 'p': case 'P': left = '?'; right = '1'; break;
8✔
6800
   case 'n': case 'N': left = '?'; right = '0'; break;
4✔
6801
   case '*':           left = '?'; right = '?'; break;
13✔
6802
   default: should_not_reach_here();
6803
   }
6804

6805
   vlog_node_t lsym = vlog_new(V_UDP_LEVEL);
28✔
6806
   vlog_set_ival(lsym, left);
28✔
6807

6808
   vlog_node_t rsym = vlog_new(V_UDP_LEVEL);
28✔
6809
   vlog_set_ival(rsym, right);
28✔
6810

6811
   vlog_node_t v = vlog_new(V_UDP_EDGE);
28✔
6812
   vlog_set_subkind(v, V_UDP_SYMBOL_INPUT);
28✔
6813
   vlog_set_left(v, lsym);
28✔
6814
   vlog_set_right(v, rsym);
28✔
6815

6816
   vlog_set_loc(v, CURRENT_LOC);
28✔
6817
   return v;
28✔
6818
}
6819

6820
static void p_level_input_list(vlog_node_t entry)
39✔
6821
{
6822
   // level_symbol { level_symbol }
6823

6824
   BEGIN("level input list");
78✔
6825

6826
   do {
90✔
6827
      vlog_add_param(entry, p_level_symbol());
90✔
6828
   } while (not_at_token(tCOLON));
90✔
6829
}
39✔
6830

6831
static vlog_node_t p_edge_indicator(void)
101✔
6832
{
6833
   // ( level_symbol level_symbol ) | edge_symbol
6834

6835
   BEGIN("edge indicator");
202✔
6836

6837
   switch (peek()) {
101✔
6838
   case tUDPEDGE:
28✔
6839
      return p_edge_symbol();
28✔
6840
   case tLPAREN:
73✔
6841
      {
6842
         consume(tLPAREN);
73✔
6843

6844
         vlog_node_t v = vlog_new(V_UDP_EDGE);
73✔
6845
         vlog_set_left(v, p_level_symbol());
73✔
6846
         vlog_set_right(v, p_level_symbol());
73✔
6847

6848
         consume(tRPAREN);
73✔
6849

6850
         vlog_set_loc(v, CURRENT_LOC);
73✔
6851
         return v;
73✔
6852
      }
UNCOV
6853
      break;
×
UNCOV
6854
   default:
×
6855
      should_not_reach_here();
6856
   }
6857
}
6858

6859
static void p_seq_input_list(vlog_node_t entry)
101✔
6860
{
6861
   // level_input_list | edge_input_list
6862

6863
   BEGIN("sequential input list");
202✔
6864

6865
   bool have_edge = false;
101✔
6866
   do {
201✔
6867
      switch (peek()) {
201✔
6868
      case tUDPEDGE:
101✔
6869
      case tLPAREN:
6870
         vlog_add_param(entry, p_edge_indicator());
101✔
6871
         if (have_edge)
101✔
6872
            parse_error(&state.last_loc, "a sequential input list may have at "
1✔
6873
                        "most one edge indicator");
6874
         have_edge = true;
6875
         break;
6876

6877
      case tUDPLEVEL:
100✔
6878
         vlog_add_param(entry, p_level_symbol());
100✔
6879
         break;
100✔
6880

6881
      default:
×
UNCOV
6882
         one_of(tUDPEDGE, tUDPIND, tUDPLEVEL);
×
UNCOV
6883
         break;
×
6884
      }
6885
   } while (not_at_token(tCOLON));
201✔
6886
}
101✔
6887

6888
static vlog_node_t p_combinational_entry(void)
39✔
6889
{
6890
   // level_input_list : output_symbol ;
6891

6892
   BEGIN("combinational entry");
78✔
6893

6894
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
39✔
6895
   p_level_input_list(v);
39✔
6896

6897
   consume(tCOLON);
39✔
6898

6899
   vlog_add_param(v, p_output_symbol());
39✔
6900

6901
   consume(tSEMI);
39✔
6902

6903
   vlog_set_loc(v, CURRENT_LOC);
39✔
6904
   return v;
39✔
6905
}
6906

6907
static vlog_node_t p_combinational_body(void)
12✔
6908
{
6909
   // table combinational_entry { combinational_entry } endtable
6910

6911
   BEGIN("combinational UDP body");
24✔
6912

6913
   consume(tTABLE);
12✔
6914

6915
   scan_as_udp();
12✔
6916

6917
   vlog_node_t v = vlog_new(V_UDP_TABLE);
12✔
6918
   vlog_set_subkind(v, V_UDP_COMB);
12✔
6919
   vlog_set_ident(v, ident_new("combinational"));
12✔
6920

6921
   do {
39✔
6922
      vlog_add_param(v, p_combinational_entry());
39✔
6923
   } while (not_at_token(tENDTABLE));
39✔
6924

6925
   scan_as_verilog();
12✔
6926

6927
   consume(tENDTABLE);
12✔
6928

6929
   vlog_set_loc(v, CURRENT_LOC);
12✔
6930
   return v;
12✔
6931
}
6932

6933
static vlog_node_t p_sequential_entry(void)
101✔
6934
{
6935
   // seq_input_list : current_state : next_state ;
6936

6937
   BEGIN("sequential entry");
202✔
6938

6939
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
101✔
6940
   p_seq_input_list(v);
101✔
6941

6942
   consume(tCOLON);
101✔
6943

6944
   vlog_add_param(v, p_level_symbol());
101✔
6945

6946
   consume(tCOLON);
101✔
6947

6948
   vlog_add_param(v, p_next_state());
101✔
6949

6950
   consume(tSEMI);
101✔
6951

6952
   vlog_set_loc(v, CURRENT_LOC);
101✔
6953
   return v;
101✔
6954
}
6955

6956
static vlog_node_t p_udp_initial_statement(void)
6✔
6957
{
6958
   // initial output_port_identifier = init_val ;
6959

6960
   BEGIN("UDP initial statement");
12✔
6961

6962
   consume(tINITIAL);
6✔
6963

6964
   vlog_node_t ref = vlog_new(V_REF);
6✔
6965
   vlog_set_ident(ref, p_identifier());
6✔
6966
   vlog_set_loc(ref, &state.last_loc);
6✔
6967

6968
   vlog_symtab_lookup(symtab, ref);
6✔
6969

6970
   consume(tEQ);
6✔
6971

6972
   vlog_node_t v = vlog_new(V_BASSIGN);
6✔
6973
   vlog_set_target(v, ref);
6✔
6974
   vlog_set_value(v, p_integral_number());
6✔
6975

6976
   consume(tSEMI);
6✔
6977

6978
   vlog_set_loc(v, CURRENT_LOC);
6✔
6979
   return v;
6✔
6980
}
6981

6982
static vlog_node_t p_sequential_body(void)
15✔
6983
{
6984
   // [ udp_initial_statement ] table sequential_entry
6985
   //     { sequential_entry } endtable
6986

6987
   BEGIN("sequential UDP body");
30✔
6988

6989
   vlog_node_t v = vlog_new(V_UDP_TABLE);
15✔
6990
   vlog_set_subkind(v, V_UDP_SEQ);
15✔
6991
   vlog_set_ident(v, ident_new("sequential"));
15✔
6992

6993
   if (peek() == tINITIAL)
15✔
6994
      vlog_add_stmt(v, p_udp_initial_statement());
6✔
6995

6996
   consume(tTABLE);
15✔
6997

6998
   scan_as_udp();
15✔
6999

7000
   do {
101✔
7001
      vlog_add_param(v, p_sequential_entry());
101✔
7002
   } while (not_at_token(tENDTABLE));
101✔
7003

7004
   scan_as_verilog();
15✔
7005

7006
   consume(tENDTABLE);
15✔
7007

7008
   vlog_set_loc(v, CURRENT_LOC);
15✔
7009
   return v;
15✔
7010
}
7011

7012
static vlog_node_t p_udp_body(bool has_reg)
27✔
7013
{
7014
   // combinational_body | sequential_body
7015

7016
   BEGIN("UDP body");
54✔
7017

7018
   if (has_reg)
27✔
7019
      return p_sequential_body();
15✔
7020
   else
7021
      return p_combinational_body();
12✔
7022
}
7023

7024
static vlog_node_t p_udp_ansi_declaration(bool *has_reg)
1✔
7025
{
7026
   // { attribute_instance } primitive udp_identifier
7027
   //    ( udp_declaration_port_list ) ;
7028

7029
   BEGIN("UDP ANSI declaration");
2✔
7030

7031
   optional_attributes();
1✔
7032

7033
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
1✔
7034

7035
   consume(tPRIMITIVE);
1✔
7036

7037
   ident_t id, ext;
1✔
7038
   p_external_identifier(&id, &ext);
1✔
7039
   vlog_set_ident2(udp, id);
1✔
7040

7041
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
1✔
7042
   vlog_set_ident(udp, qual);
1✔
7043

7044
   vlog_symtab_push(symtab, udp);
1✔
7045

7046
   consume(tLPAREN);
1✔
7047

7048
   p_udp_declaration_port_list(udp, has_reg);
1✔
7049

7050
   consume(tRPAREN);
1✔
7051
   consume(tSEMI);
1✔
7052

7053
   vlog_set_loc(udp, CURRENT_LOC);
1✔
7054
   return udp;
1✔
7055
}
7056

7057
static vlog_node_t p_udp_declaration(void)
27✔
7058
{
7059
   // udp_nonansi_declaration udp_port_declaration { udp_port_declaration }
7060
   //        udp_body endprimitive [ : udp_identifier ]
7061
   //   | udp_ansi_declaration udp_body endprimitive [ : udp_identifier ]
7062
   //   | extern udp_nonansi_declaration
7063
   //   | extern udp_ansi_declaration
7064
   //   | { attribute_instance } primitive udp_identifier ( .* ) ;
7065
   //        { udp_port_declaration } udp_body endprimitive [ : udp_identifier ]
7066

7067
   BEGIN("UDP declaration");
54✔
7068

7069
   bool has_reg = false;
27✔
7070
   vlog_node_t udp;
27✔
7071
   if (peek_nth(4) == tID) {
27✔
7072
      udp = p_udp_nonansi_declaration();
26✔
7073

7074
      vlog_symtab_push(symtab, udp);
26✔
7075

7076
      do {
65✔
7077
         p_udp_port_declaration(udp, &has_reg);
65✔
7078
      } while (not_at_token(tTABLE, tINITIAL));
65✔
7079

7080
      const int nports = vlog_ports(udp);
26✔
7081
      for (int i = 0; i < nports; i++)
106✔
7082
         vlog_symtab_lookup(symtab, vlog_port(udp, i));
80✔
7083
   }
7084
   else
7085
      udp = p_udp_ansi_declaration(&has_reg);
1✔
7086

7087
   vlog_add_stmt(udp, p_udp_body(has_reg));
27✔
7088

7089
   vlog_symtab_pop(symtab);
27✔
7090

7091
   consume(tENDPRIMITIVE);
27✔
7092

7093
   return udp;
27✔
7094
}
7095

7096
static void p_package_item(vlog_node_t parent)
24✔
7097
{
7098
   // package_or_generate_item_declaration | anonymous_program
7099
   //   | package_export_declaration | timeunits_declaration
7100

7101
   BEGIN("package item");
48✔
7102

7103
   p_package_or_generate_item_declaration(parent);
24✔
7104
}
24✔
7105

7106
static vlog_node_t p_package_declaration(void)
5✔
7107
{
7108
   // { attribute_instance } package [ lifetime ] package_identifier ;
7109
   //    [ timeunits_declaration ] { { attribute_instance } package_item }
7110
   // endpackage [ : package_identifier ]
7111

7112
   BEGIN("package declaration");
10✔
7113

7114
   consume(tPACKAGE);
5✔
7115

7116
   param_kind = V_LOCALPARAM;
5✔
7117

7118
   if (scan(tSTATIC, tAUTOMATIC))
5✔
UNCOV
7119
      p_lifetime();
×
7120

7121
   vlog_node_t v = vlog_new(V_PACKAGE);
5✔
7122

7123
   ident_t id, ext;
5✔
7124
   p_external_identifier(&id, &ext);
5✔
7125
   vlog_set_ident2(v, id);
5✔
7126

7127
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
5✔
7128
   vlog_set_ident(v, qual);
5✔
7129

7130
   consume(tSEMI);
5✔
7131

7132
   vlog_symtab_push(symtab, v);
5✔
7133

7134
   while (not_at_token(tENDPACKAGE)) {
16✔
7135
      optional_attributes();
11✔
7136
      p_package_item(v);
11✔
7137
   }
7138

7139
   vlog_symtab_pop(symtab);
5✔
7140

7141
   consume(tENDPACKAGE);
5✔
7142

7143
   if (optional(tCOLON)) {
5✔
7144
      ident_t name = p_identifier();
2✔
7145
      if (id != name)
2✔
7146
         error_at(&state.last_loc, "'%s' does not match package name '%s'",
1✔
7147
                  istr(name), istr(id));
7148
   }
7149

7150
   vlog_set_loc(v, CURRENT_LOC);
5✔
7151
   return v;
5✔
7152
}
7153

7154
static vlog_node_t p_program_nonansi_header(void)
11✔
7155
{
7156
   // { attribute_instance } program [ lifetime ] program_identifier
7157
   //    { package_import_declaration } [ parameter_port_list ] list_of_ports ;
7158

7159
   BEGIN("program non-ANSI header");
22✔
7160

7161
   optional_attributes();
11✔
7162

7163
   vlog_node_t v = vlog_new(V_PROGRAM);
11✔
7164

7165
   consume(tPROGRAM);
11✔
7166

7167
   ident_t id, ext;
11✔
7168
   p_external_identifier(&id, &ext);
11✔
7169
   vlog_set_ident2(v, id);
11✔
7170

7171
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
11✔
7172
   vlog_set_ident(v, qual);
11✔
7173

7174
   consume(tSEMI);
11✔
7175

7176
   vlog_set_loc(v, CURRENT_LOC);
11✔
7177
   return v;
11✔
7178
}
7179

7180
static void p_non_port_program_item(vlog_node_t parent)
38✔
7181
{
7182
   // { attribute_instance } continuous_assign
7183
   //   | { attribute_instance } module_or_generate_item_declaration
7184
   //   | { attribute_instance } initial_construct
7185
   //   | { attribute_instance } final_construct
7186
   //   | { attribute_instance } concurrent_assertion_item
7187
   //   | timeunits_declaration
7188
   //   | program_generate_item
7189

7190
   BEGIN("non-port program item");
76✔
7191

7192
   optional_attributes();
38✔
7193

7194
   switch (peek()) {
38✔
7195
   case tINITIAL:
11✔
7196
      vlog_add_stmt(parent, p_initial_construct());
11✔
7197
      break;
11✔
7198
   default:
27✔
7199
      p_module_or_generate_item_declaration(parent);
27✔
7200
      break;
27✔
7201
   }
7202
}
38✔
7203

7204
static vlog_node_t p_program_declaration(void)
11✔
7205
{
7206
   // program_nonansi_header [ timeunits_declaration ] { program_item }
7207
   //       endprogram [ : program_identifier ]
7208
   //   | program_ansi_header [ timeunits_declaration ]
7209
   //       { non_port_program_item }
7210
   //   | { attribute_instance } program program_identifier ( .* ) ;
7211
   //       [ timeunits_declaration ] { program_item } endprogram
7212
   //       [ : program_identifier ]
7213
   //   | extern program_nonansi_header
7214
   //   | extern program_ansi_header
7215

7216
   BEGIN("program declaration");
22✔
7217

7218
   vlog_node_t v = p_program_nonansi_header();
11✔
7219

7220
   while (not_at_token(tENDPROGRAM))
49✔
7221
      p_non_port_program_item(v);
38✔
7222

7223
   consume(tENDPROGRAM);
11✔
7224

7225
   if (optional(tCOLON)) {
11✔
7226
      ident_t name = p_identifier();
1✔
7227
      if (name != vlog_ident2(v))
1✔
7228
         parse_error(&state.last_loc, "'%s' does not match program name '%s'",
1✔
7229
                     istr(name), istr(vlog_ident2(v)));
7230
   }
7231

7232
   vlog_set_loc(v, CURRENT_LOC);
11✔
7233
   return v;
11✔
7234
}
7235

7236
static vlog_node_t p_description(void)
950✔
7237
{
7238
   // module_declaration | udp_declaration | interface_declaration
7239
   //   | program_declaration | package_declaration
7240
   //   | { attribute_instance } package_item
7241
   //   | { attribute_instance } bind_directive
7242
   //   | config_declaration
7243

7244
   BEGIN("description");
1,900✔
7245

7246
   skip_over_attributes();
950✔
7247

7248
   switch (peek()) {
950✔
7249
   case tMODULE:
899✔
7250
      return p_module_declaration();
899✔
7251
   case tPRIMITIVE:
27✔
7252
      return p_udp_declaration();
27✔
7253
   case tPACKAGE:
5✔
7254
      return p_package_declaration();
5✔
7255
   case tPROGRAM:
11✔
7256
      return p_program_declaration();
11✔
7257
   case tCLASS:
8✔
7258
   case tTYPEDEF:
7259
   case tIMPORT:
7260
      {
7261
         vlog_node_t v = vlog_new(V_NAMESPACE);
8✔
7262

7263
         char hash[SHA_HEX_LEN];
8✔
7264
         get_hex_hash(loc_file_str(&state.last_loc), hash);
8✔
7265

7266
         ident_t name = ident_sprintf("%s$%d", hash, next_namespace++);
8✔
7267
         vlog_set_ident(v, ident_prefix(lib_name(lib_work()), name, '.'));
8✔
7268

7269
         do {
13✔
7270
            p_package_item(v);
13✔
7271
         } while (scan(tCLASS, tTYPEDEF, tIMPORT));
13✔
7272

7273
         vlog_set_loc(v, CURRENT_LOC);
8✔
7274
         return v;
8✔
7275
      }
UNCOV
7276
   default:
×
UNCOV
7277
      expect(tPRIMITIVE, tMODULE, tPACKAGE, tPROGRAM, tCLASS, tTYPEDEF,
×
7278
             tIMPORT);
UNCOV
7279
      return NULL;
×
7280
   }
7281
}
7282

7283
static void p_timescale_compiler_directive(void)
21✔
7284
{
7285
   // `timescale time_unit / time_precision
7286

7287
   BEGIN("timescale compiler directive");
42✔
7288

7289
   consume(tTIMESCALE);
21✔
7290

7291
   uint64_t unit_value = 1;
21✔
7292
   if (consume(tUNSNUM))
21✔
7293
      unit_value = atoll(state.last_lval.str);
20✔
7294

7295
   const char *unit_name = "fs";
21✔
7296
   if (consume(tID))
21✔
7297
      unit_name = istr(state.last_lval.ident);
21✔
7298

7299
   consume(tOVER);
21✔
7300

7301
   uint64_t prec_value = 1;
21✔
7302
   if (consume(tUNSNUM))
21✔
7303
      prec_value = atoll(state.last_lval.str);
20✔
7304

7305
   const char *prec_name = "fs";
21✔
7306
   if (consume(tID))
21✔
7307
      prec_name = istr(state.last_lval.ident);
20✔
7308

7309
   set_timescale(unit_value, unit_name, prec_value, prec_name, CURRENT_LOC);
21✔
7310
}
21✔
7311

7312
static void p_defaultnettype_compiler_directive(void)
12✔
7313
{
7314
   // `default_nettype wire | tri | tri0 | tri1 | wand | triand | wor
7315
   //    | trior | trireg | uwire | none
7316

7317
   BEGIN("default_nettype directive");
24✔
7318

7319
   consume(tDEFNETTYPE);
12✔
7320

7321
   switch (one_of(tWIRE, tTRI, tTRI0, tTRI1, tWAND, tTRIAND, tWOR, tTRIOR,
12✔
7322
                  tTRIREG, tUWIRE, tNONE)) {
7323
   case tWIRE: implicit_kind = V_NET_WIRE; break;
1✔
7324
   case tNONE: implicit_kind = V_NET_NONE; break;
1✔
7325
   }
7326
}
12✔
7327

7328
static void p_unconnected_drive_directive(void)
2✔
7329
{
7330
   // `unconnected_drive pull0 | pull1
7331

7332
   BEGIN("unconnected_drive directive");
4✔
7333

7334
   consume(tUNCTDRIVE);
2✔
7335

7336
   // TODO set default drive for unconnected nets
7337
   one_of(tPULL0, tPULL1);
2✔
7338
}
2✔
7339

7340
static void p_nounconnected_drive_directive(void)
1✔
7341
{
7342
   // `nounconnected_drive
7343

7344
   BEGIN("nounconnected_drive directive");
2✔
7345

7346
   consume(tNOUNCTDRIVE);
1✔
7347

7348
   // TODO reset default drive for unconnected nets
7349
}
1✔
7350

7351
static void p_keywords_directive(void)
8✔
7352
{
7353
   // `begin_keywords "version_specifier"
7354

7355
   BEGIN("keywords directive");
16✔
7356

7357
   consume(tBEGINKEYWORDS);
8✔
7358

7359
   if (consume(tSTRING)) {
8✔
7360
      vlog_version_t vers;
7✔
7361
      if (parse_verilog_version(tb_get(state.last_lval.text), &vers))
7✔
7362
         push_keywords(vers);
6✔
7363
      else
7364
         error_at(&state.last_loc, "\"%s\" is not a recognised Verilog or "
1✔
7365
                  "System Verilog version", tb_get(state.last_lval.text));
7366

7367
      tb_free(state.last_lval.text);
7✔
7368
   }
7369
}
8✔
7370

7371
static void p_endkeywords_directive(void)
7✔
7372
{
7373
   // `end_keywords
7374

7375
   BEGIN("endkeywords directive");
14✔
7376

7377
   consume(tENDKEYWORDS);
7✔
7378

7379
   if (!pop_keywords())
7✔
7380
      error_at(&state.last_loc, "`end_keywords directive without matching "
1✔
7381
               "`begin_keywords");
7382
}
7✔
7383

7384
static void p_resetall_directive(void)
1✔
7385
{
7386
   // `resetall
7387

7388
   BEGIN("resetall directive");
2✔
7389

7390
   consume(tRESETALL);
1✔
7391

7392
   implicit_kind = V_NET_WIRE;
1✔
7393
}
1✔
7394

7395
static void p_directive_list(void)
1,718✔
7396
{
7397
   BEGIN("directive list");
3,436✔
7398

7399
   for (;;) {
1,770✔
7400
      switch (peek()) {
1,770✔
7401
      case tDEFNETTYPE:
12✔
7402
         p_defaultnettype_compiler_directive();
12✔
7403
         break;
12✔
7404
      case tTIMESCALE:
21✔
7405
         p_timescale_compiler_directive();
21✔
7406
         break;
21✔
7407
      case tUNCTDRIVE:
2✔
7408
         p_unconnected_drive_directive();
2✔
7409
         break;
2✔
7410
      case tNOUNCTDRIVE:
1✔
7411
         p_nounconnected_drive_directive();
1✔
7412
         break;
1✔
7413
      case tBEGINKEYWORDS:
8✔
7414
         p_keywords_directive();
8✔
7415
         break;
8✔
7416
      case tENDKEYWORDS:
7✔
7417
         p_endkeywords_directive();
7✔
7418
         break;
7✔
7419
      case tRESETALL:
1✔
7420
         p_resetall_directive();
1✔
7421
         break;
1✔
7422
      default:
7423
         return;
1,718✔
7424
      }
7425
   }
7426
}
7427

7428
static vlog_node_t end_of_file(void)
768✔
7429
{
7430
   vlog_symtab_pop(symtab);
768✔
7431
   vlog_symtab_free(symtab);
768✔
7432
   symtab = NULL;
768✔
7433
   return NULL;
768✔
7434
}
7435

7436
static vlog_node_t p_source_text(void)
950✔
7437
{
7438
   // [ timeunits_declaration ] { description }
7439

7440
   BEGIN("source text");
1,900✔
7441

7442
   for (;;) {
950✔
7443
      if (peek() == tEOF) {
950✔
UNCOV
7444
         discard_global_arena();
×
UNCOV
7445
         return end_of_file();
×
7446
      }
7447

7448
      vlog_node_t v = p_description();
950✔
7449
      if (v == NULL || is_top_level(v))
950✔
7450
         return v;
950✔
7451
   }
7452
}
7453

7454
vlog_node_t vlog_parse(void)
1,718✔
7455
{
7456
   state.n_correct = RECOVER_THRESH;
1,718✔
7457
   param_kind = V_PARAM_DECL;
1,718✔
7458

7459
   for (int i = 0; i < ARRAY_LEN(atom_types); i++)
18,898✔
7460
      atom_types[i] = NULL;
17,180✔
7461

7462
   scan_as_verilog();
1,718✔
7463

7464
   if (symtab == NULL) {
1,718✔
7465
      symtab = vlog_symtab_new();
770✔
7466
      vlog_symtab_push(symtab, NULL);   // Compilation unit scope
770✔
7467
      vlog_symtab_poison(symtab, error_marker());
770✔
7468
   }
7469

7470
   p_directive_list();
1,718✔
7471

7472
   if (peek() == tEOF)
1,718✔
7473
      return end_of_file();
768✔
7474

7475
   make_new_arena();
950✔
7476

7477
   return p_source_text();
950✔
7478
}
7479

7480
void reset_verilog_parser(void)
1,505✔
7481
{
7482
   state.n_correct = RECOVER_THRESH;
1,505✔
7483
   state.tokenq_head = state.tokenq_tail = 0;
1,505✔
7484
   state.lex_fn = processed_yylex;
1,505✔
7485
   state.error_fn = vlog_parse_error_cb;
1,505✔
7486

7487
   implicit_kind = V_NET_WIRE;
1,505✔
7488
   last_attr = NULL;
1,505✔
7489
   next_namespace = 1;
1,505✔
7490

7491
   if (symtab != NULL) {
1,505✔
UNCOV
7492
      vlog_symtab_free(symtab);
×
UNCOV
7493
      symtab = NULL;
×
7494
   }
7495
}
1,505✔
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