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

nickg / nvc / 26395823927

25 May 2026 10:27AM UTC coverage: 92.265% (-0.004%) from 92.269%
26395823927

push

github

nickg
Improve checking for Verilog constant expressions

78 of 87 new or added lines in 5 files covered. (89.66%)

246 existing lines in 8 files now uncovered.

78777 of 85381 relevant lines covered (92.27%)

630338.01 hits per line

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

95.82
/src/vlog/vlog-parse.c
1
//
2
//  Copyright (C) 2024-2026  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
                                                vlog_kind_t kind);
58
static vlog_node_t p_variable_lvalue(void);
59
static vlog_node_t p_select(ident_t id);
60
static vlog_net_kind_t p_net_type(void);
61
static void p_module_or_generate_item(vlog_node_t mod);
62
static void p_block_item_declaration(vlog_node_t parent);
63
static vlog_node_t p_attribute_instance(void);
64
static vlog_node_t  p_drive_strength(void);
65
static vlog_strength_t p_strength0(void);
66
static vlog_strength_t p_strength1(void);
67

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

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

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

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

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

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

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

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

127
      args[i].parsed *= args[i].value;
50✔
128
   }
129

130
   // TODO: do something with parsed scale/precision
131
}
25✔
132

133
static void skip_over_attributes(void)
12,872✔
134
{
135
   while (peek() == tATTRBEGIN)
12,892✔
136
      last_attr = p_attribute_instance();
20✔
137
}
12,872✔
138

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

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

155
   last_attr = NULL;
82,295✔
156
}
82,295✔
157

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

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

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

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

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

196
      vlog_node_t right = vlog_new(V_NUMBER);
213✔
197
      vlog_set_number(right, number_from_int(0));
213✔
198

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

204
      atom_types[dt] = r;
213✔
205
   }
206

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

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

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

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

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

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

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

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

282
      return logic_type();
1✔
283
   }
284

285
   return v;
286
}
287

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

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

301
static ident_t p_identifier(void)
52,166✔
302
{
303
   if (consume(tID))
52,166✔
304
      return state.last_lval.ident;
52,165✔
305
   else
306
      return error_marker();
1✔
307
}
308

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

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

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

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

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

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

338
   (void)p_identifier();
27✔
339

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

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

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

350
   consume(tATTRBEGIN);
27✔
351

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

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

358
   consume(tATTREND);
27✔
359

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

364
static vlog_node_t p_unsigned_number(void)
22,030✔
365
{
366
   // decimal_digit { _ | decimal_digit }
367

368
   BEGIN("unsigned number");
44,060✔
369

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

378
   vlog_node_t v = vlog_new(V_NUMBER);
22,030✔
379
   vlog_set_number(v, n);
22,030✔
380
   vlog_set_loc(v, CURRENT_LOC);
22,030✔
381
   return v;
22,030✔
382
}
383

384
static vlog_node_t p_integral_number(void)
39,851✔
385
{
386
   // decimal_number | octal_number | binary_number | hex_number
387

388
   BEGIN("integral number");
79,702✔
389

390
   if (peek() == tUNSNUM)
39,851✔
391
      return p_unsigned_number();
17,336✔
392
   else {
393
      number_t n;
22,515✔
394
      if (consume(tNUMBER)) {
22,515✔
395
         n = number_new(state.last_lval.str, &state.last_loc);
22,514✔
396
         free(state.last_lval.str);
22,514✔
397
      }
398
      else
399
         n = number_from_int(0);
1✔
400

401
      vlog_node_t v = vlog_new(V_NUMBER);
22,515✔
402
      vlog_set_number(v, n);
22,515✔
403
      vlog_set_loc(v, CURRENT_LOC);
22,515✔
404
      return v;
22,515✔
405
   }
406
}
407

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

413
   BEGIN("real number");
1,030✔
414

415
   consume(tREAL);
515✔
416

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

423
static vlog_node_t p_number(void)
40,355✔
424
{
425
   // integral_number | real_number
426

427
   BEGIN("number");
80,710✔
428

429
   if (peek() == tREAL)
40,355✔
430
      return p_real_number();
510✔
431
   else
432
      return p_integral_number();
39,845✔
433
}
434

435
static vlog_node_t p_string_literal(void)
6,567✔
436
{
437
   // " { Any_ASCII_Characters } "
438

439
   BEGIN("string literal");
13,134✔
440

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

450
   vlog_node_t v = vlog_new(V_STRING);
6,567✔
451
   vlog_set_number(v, n);
6,567✔
452
   vlog_set_loc(v, CURRENT_LOC);
6,567✔
453
   return v;
13,134✔
454
}
455

456
static vlog_node_t p_primary_literal(void)
46,922✔
457
{
458
   // number | time_literal | unbased_unsized_literal | string_literal
459

460
   BEGIN("primary literal");
93,844✔
461

462
   switch (peek()) {
46,922✔
463
   case tNUMBER:
40,355✔
464
   case tUNSNUM:
465
   case tREAL:
466
      return p_number();
40,355✔
467
   case tSTRING:
6,567✔
468
      return p_string_literal();
6,567✔
469
   default:
×
470
      one_of(tNUMBER, tUNSNUM, tREAL, tSTRING);
×
UNCOV
471
      return dummy_expression();
×
472
   }
473
}
474

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

480
   EXTEND("constant select");
1,594✔
481

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

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

494
   BEGIN("constant expression");
20,932✔
495

496
   // Checked for constant-ness later
497
   return p_expression();
10,466✔
498
}
499

500
static void p_constant_range(vlog_node_t *left, vlog_node_t *right)
4,284✔
501
{
502
   // constant_expression : constant_expression
503

504
   BEGIN("constant range");
8,568✔
505

506
   *left = p_constant_expression();
4,284✔
507

508
   consume(tCOLON);
4,284✔
509

510
   *right = p_constant_expression();
4,284✔
511
}
4,284✔
512

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

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

519
   return p_constant_expression();
2✔
520
}
521

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

527
   return p_constant_expression();
8✔
528
}
529

530
static vlog_node_t p_packed_dimension(void)
4,171✔
531
{
532
   // [ constant_range ] | unsized_dimension
533

534
   BEGIN("packed dimension");
8,342✔
535

536
   consume(tLSQUARE);
4,171✔
537

538
   vlog_node_t left, right;
4,171✔
539
   p_constant_range(&left, &right);
4,171✔
540

541
   consume(tRSQUARE);
4,171✔
542

543
   vlog_node_t v = vlog_new(V_DIMENSION);
4,171✔
544
   vlog_set_subkind(v, V_DIM_PACKED);
4,171✔
545
   vlog_set_left(v, left);
4,171✔
546
   vlog_set_right(v, right);
4,171✔
547
   vlog_set_loc(v, CURRENT_LOC);
4,171✔
548

549
   return v;
4,171✔
550
}
551

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

556
   BEGIN("unpacked dimension");
226✔
557

558
   consume(tLSQUARE);
113✔
559

560
   vlog_node_t left, right;
113✔
561
   p_constant_range(&left, &right);
113✔
562

563
   consume(tRSQUARE);
113✔
564

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

571
   return v;
113✔
572
}
573

574
static vlog_node_t p_data_type_or_void(void)
123✔
575
{
576
   // data_type | void
577

578
   BEGIN("data type or void");
246✔
579

580
   if (optional(tVOID))
123✔
581
      return NULL;
582
   else
583
      return p_data_type();
122✔
584
}
585

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

591
   BEGIN("struct or union member");
152✔
592

593
   optional_attributes();
76✔
594

595
   vlog_node_t dt = p_data_type_or_void();
76✔
596
   p_list_of_variable_decl_assignments(v, dt, V_VAR_DECL);
76✔
597

598
   consume(tSEMI);
76✔
599
}
76✔
600

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

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

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

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

615
   vlog_add_decl(parent, v);
73✔
616

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

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

625
   BEGIN("integer atom type");
666✔
626

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

637
   return make_integer_atom_type(dt);
333✔
638
}
639

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

644
   BEGIN("integer vector type");
7,240✔
645

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

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

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

663
   BEGIN("non-integer type");
298✔
664

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

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

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

682
   BEGIN("struct or union");
82✔
683

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

697
static vlog_flags_t p_signing(void)
137✔
698
{
699
   // signed | unsigned
700

701
   BEGIN("signing");
274✔
702

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

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

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

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

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

732
         return v;
733
      }
734

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

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

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

747
         return v;
748
      }
749

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

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

769
   BEGIN("data type");
8,428✔
770

771
   switch (peek()) {
4,214✔
772
   case tBIT:
3,614✔
773
   case tLOGIC:
774
   case tREG:
775
      {
776
         vlog_node_t v = p_integer_vector_type();
3,614✔
777

778
         if (scan(tSIGNED, tUNSIGNED))
3,614✔
779
            vlog_set_flags(v, p_signing());
69✔
780

781
         while (peek() == tLSQUARE)
6,659✔
782
            vlog_add_range(v, p_packed_dimension());
3,045✔
783

784
         return v;
785
      }
786

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

796
         if (scan(tSIGNED, tUNSIGNED))
322✔
797
            vlog_set_flags(v, p_signing());
1✔
798
         else
799
            vlog_set_flags(v, VLOG_F_SIGNED);
321✔
800

801
         return v;
802
      }
803

804
   case tSVREAL:
149✔
805
   case tREALTIME:
806
   case tSHORTREAL:
807
      return p_non_integer_type();
149✔
808

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

814
         if (optional(tPACKED)) {
41✔
815
            vlog_set_flags(v, VLOG_F_PACKED);
34✔
816

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

821
         consume(tLBRACE);
41✔
822

823
         vlog_symtab_push(symtab, v);
41✔
824

825
         do {
76✔
826
            p_struct_union_member(v);
76✔
827
         } while (not_at_token(tRBRACE));
76✔
828

829
         vlog_symtab_pop(symtab);
41✔
830

831
         consume(tRBRACE);
41✔
832

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

836
         vlog_set_loc(v, CURRENT_LOC);
41✔
837
         return v;
41✔
838
      }
839

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

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

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

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

855
         consume(tLBRACE);
26✔
856

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

861
         consume(tRBRACE);
26✔
862

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

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

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

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

878
         return v;
1✔
879
      }
880

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

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

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

892
         return v;
4✔
893
      }
894

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

903
static vlog_node_t p_implicit_data_type(void)
2,238✔
904
{
905
   // [ signing ] { packed_dimension }
906

907
   BEGIN("implicit data type");
4,476✔
908

909
   vlog_node_t v = vlog_new(V_DATA_TYPE);
2,238✔
910
   vlog_set_subkind(v, DT_IMPLICIT);
2,238✔
911

912
   if (scan(tSIGNED, tUNSIGNED))
2,238✔
913
      vlog_set_flags(v, p_signing());
67✔
914

915
   while (peek() == tLSQUARE)
3,355✔
916
      vlog_add_range(v, p_packed_dimension());
1,117✔
917

918
   vlog_set_loc(v, CURRENT_LOC);
2,238✔
919
   return v;
2,238✔
920
}
921

922
static vlog_node_t p_data_type_or_implicit(void)
6,120✔
923
{
924
   // data_type | implicit_data_type
925

926
   BEGIN("data type or implicit");
12,240✔
927

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

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

963
   BEGIN("net port type");
1,098✔
964

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

971
   *dt = p_data_type_or_implicit();
549✔
972
}
549✔
973

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

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

980
   return p_data_type();
24✔
981
}
982

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

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

989
   return p_var_data_type();
24✔
990
}
991

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

998
   BEGIN("list of port identifiers");
832✔
999

1000
   do {
448✔
1001
      ident_t id, ext;
448✔
1002
      p_external_identifier(&id, &ext);
448✔
1003

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

1011
      vlog_add_decl(mod, v);
448✔
1012
      vlog_symtab_put(symtab, v);
448✔
1013

1014
      declare_port(mod, v);
448✔
1015
   } while (optional(tCOMMA));
448✔
1016
}
416✔
1017

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

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

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

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

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

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

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

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

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

1054
   consume(tINOUT);
1✔
1055

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

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

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

1068
   BEGIN("input declaration");
474✔
1069

1070
   consume(tINPUT);
237✔
1071

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

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

1091
   BEGIN("output declaration");
404✔
1092

1093
   consume(tOUTPUT);
202✔
1094

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

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

1121
   BEGIN("port declaration");
880✔
1122

1123
   switch (peek()) {
440✔
1124
   case tINOUT: p_inout_declaration(mod); break;
1✔
1125
   case tINPUT: p_input_declaration(mod); break;
237✔
1126
   case tOUTPUT: p_output_declaration(mod); break;
202✔
1127
   default: should_not_reach_here();
1128
   }
1129
}
440✔
1130

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

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

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

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

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

1154
   BEGIN("part select range");
3,466✔
1155

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

1162
   vlog_set_subkind(ps, kind);
1,733✔
1163
   vlog_set_right(ps, p_constant_expression());
1,733✔
1164
}
1,733✔
1165

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

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

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

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

1178
   consume(tDOT);
10✔
1179

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

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

1191
static vlog_node_t p_select(ident_t id)
42,881✔
1192
{
1193
   // [ { . member_identifier bit_select } . member_identifier ]
1194
   //    { [ expression ] } [ [ part_select_range ] ]
1195

1196
   EXTEND("select");
85,762✔
1197

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

1210
      vlog_symtab_lookup(symtab, prefix);
42,874✔
1211

1212
      while (optional(tDOT)) {
43,147✔
1213
         vlog_node_t ref = vlog_new(V_MEMBER_REF);
273✔
1214
         vlog_set_ident(ref, p_identifier());
273✔
1215
         vlog_set_value(ref, prefix);
273✔
1216
         vlog_set_loc(ref, CURRENT_LOC);
273✔
1217

1218
         vlog_symtab_lookup(symtab, ref);
273✔
1219

1220
         prefix = ref;
273✔
1221
      }
1222
   }
1223

1224
   if (optional(tLSQUARE)) {
42,881✔
1225
      do {
2,811✔
1226
         vlog_node_t expr = p_expression();
2,811✔
1227
         if (scan(tCOLON, tINDEXPOS, tINDEXNEG)) {
2,811✔
1228
            vlog_node_t ps = vlog_new(V_PART_SELECT);
1,733✔
1229
            vlog_set_left(ps, expr);
1,733✔
1230
            vlog_set_value(ps, prefix);
1,733✔
1231

1232
            p_part_select_range(ps);
1,733✔
1233

1234
            consume(tRSQUARE);
1,733✔
1235

1236
            vlog_set_loc(ps, CURRENT_LOC);
1,733✔
1237
            return ps;
1,733✔
1238
         }
1239

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

1248
            prefix = bs;
994✔
1249
         }
1250

1251
         consume(tRSQUARE);
1,078✔
1252
      } while (optional(tLSQUARE));
1,078✔
1253
   }
1254

1255
   return prefix;
1256
}
1257

1258
static void p_list_of_arguments(vlog_node_t call)
7,360✔
1259
{
1260
   // [ expression ] { , [ expression ] } { , . identifier ( [ expression ] ) }
1261
   //    | . identifier ( [ expression ] ) { , . identifier ( [ expression ] ) }
1262

1263
   BEGIN("list of arguments");
14,720✔
1264

1265
   if (peek() == tRPAREN)
7,360✔
1266
      return;
66✔
1267

1268
   do {
14,795✔
1269
      if (peek() == tCOMMA) {
14,795✔
1270
         vlog_node_t v = vlog_new(V_EMPTY);
306✔
1271
         vlog_set_loc(v, &state.last_loc);
306✔
1272
         vlog_add_param(call, v);
306✔
1273
      }
1274
      else
1275
         vlog_add_param(call, p_expression());
14,489✔
1276
   } while (optional(tCOMMA));
14,795✔
1277
}
1278

1279
static vlog_node_t p_system_tf_call(vlog_kind_t kind)
10,163✔
1280
{
1281
   // system_tf_identifier [ ( list_of_arguments ) ]
1282

1283
   BEGIN("system task or function call");
20,326✔
1284

1285
   ident_t id = p_system_tf_identifier();
10,163✔
1286

1287
   vlog_systf_t subk;
10,163✔
1288
   switch (is_well_known(id)) {
10,163✔
1289
   case W_DLR_SIGNED:   subk = V_SYSTF_SIGNED; break;
1290
   case W_DLR_UNSIGNED: subk = V_SYSTF_UNSIGNED; break;
1291
   case W_DLR_CLOG2:    subk = V_SYSTF_CLOG2; break;
1292
   case W_DLR_SQRT:     subk = V_SYSTF_SQRT; break;
1293
   default:             subk = V_SYSTF_NONE; break;
1294
   }
1295

1296
   vlog_node_t v = vlog_new(kind);
10,163✔
1297
   vlog_set_ident(v, id);
10,163✔
1298
   vlog_set_subkind(v, subk);
10,163✔
1299

1300
   if (optional(tLPAREN)) {
10,163✔
1301
      p_list_of_arguments(v);
6,680✔
1302
      consume(tRPAREN);
6,680✔
1303
   }
1304

1305
   vlog_set_loc(v, CURRENT_LOC);
10,163✔
1306
   return v;
10,163✔
1307
}
1308

1309
static vlog_node_t p_tf_call(vlog_kind_t kind)
684✔
1310
{
1311
   // ps_or_hierarchical_tf_identifier { attribute_instance }
1312
   //    [ ( list_of_arguments ) ]
1313

1314
   BEGIN("task or function call");
1,368✔
1315

1316
   vlog_node_t v = vlog_new(kind);
684✔
1317
   vlog_set_ident(v, p_identifier());
684✔
1318

1319
   optional_attributes();
684✔
1320

1321
   if (optional(tLPAREN)) {
684✔
1322
      p_list_of_arguments(v);
677✔
1323
      consume(tRPAREN);
677✔
1324
   }
1325

1326
   vlog_set_loc(v, CURRENT_LOC);
684✔
1327
   vlog_symtab_lookup(symtab, v);
684✔
1328
   return v;
684✔
1329
}
1330

1331
static vlog_node_t p_subroutine_call(vlog_kind_t kind)
10,847✔
1332
{
1333
   // tf_call | system_tf_call | method_call | [ std:: ] randomize_call
1334

1335
   BEGIN("subroutine call");
21,694✔
1336

1337
   if (peek() == tSYSTASK)
10,847✔
1338
      return p_system_tf_call(kind);
10,163✔
1339
   else
1340
      return p_tf_call(kind);
684✔
1341
}
1342

1343
static vlog_node_t p_mintypmax_expression(void)
44,180✔
1344
{
1345
   // expression | expression : expression : expression
1346

1347
   BEGIN("mintypmax expression");
88,360✔
1348

1349
   vlog_node_t e = p_expression();
44,180✔
1350

1351
   if (optional(tCOLON)) {
44,180✔
1352
      vlog_node_t mtm = vlog_new(V_MIN_TYP_MAX);
1✔
1353
      vlog_set_left(mtm, e);
1✔
1354
      vlog_set_value(mtm, p_expression());
1✔
1355

1356
      consume(tCOLON);
1✔
1357
      vlog_set_right(mtm, p_expression());
1✔
1358

1359
      return mtm;
1✔
1360
   }
1361

1362
   return e;
1363
}
1364

1365
static vlog_node_t p_concatenation(vlog_node_t head)
333✔
1366
{
1367
   // { expression { , expression } }
1368

1369
   BEGIN_WITH_HEAD("concatenation", head);
666✔
1370

1371
   if (head == NULL) {
333✔
1372
      consume(tLBRACE);
93✔
1373
      head = p_expression();
93✔
1374
   }
1375

1376
   vlog_node_t v = vlog_new(V_CONCAT);
333✔
1377
   vlog_add_param(v, head);
333✔
1378

1379
   while (optional(tCOMMA))
735✔
1380
      vlog_add_param(v, p_expression());
402✔
1381

1382
   consume(tRBRACE);
333✔
1383

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

1388
static vlog_node_t p_multiple_concatenation(vlog_node_t head)
93✔
1389
{
1390
   // { expression concatenation }
1391

1392
   BEGIN_WITH_HEAD("multiple concatenation", head);
186✔
1393

1394
   vlog_node_t v = p_concatenation(NULL);
93✔
1395
   vlog_set_value(v, head);
93✔
1396

1397
   consume(tRBRACE);
93✔
1398

1399
   vlog_set_loc(v, CURRENT_LOC);
93✔
1400
   return v;
93✔
1401
}
1402

1403
static vlog_node_t p_package_identifier(void)
3✔
1404
{
1405
   // identifier
1406

1407
   BEGIN("package identifier");
6✔
1408

1409
   ident_t id = p_identifier();
3✔
1410

1411
   lib_t work = lib_work();
3✔
1412
   ident_t qual = ident_prefix(lib_name(work), id, '.');
3✔
1413
   object_t *obj = lib_get_generic(lib_work(), qual, NULL);
3✔
1414
   vlog_node_t v = vlog_from_object(obj);
3✔
1415
   if (v == NULL || vlog_kind(v) != V_PACKAGE) {
3✔
UNCOV
1416
      parse_error(&state.last_loc, "no package named '%pi' in working "
×
1417
                  "library", id);
UNCOV
1418
      return NULL;
×
1419
   }
1420

1421
   return v;
1422
}
1423

UNCOV
1424
static vlog_node_t p_package_scope(void)
×
1425
{
1426
   // package_identifier :: | $unit ::
1427

UNCOV
1428
   BEGIN("package scope");
×
1429

1430
   switch (peek()) {
×
UNCOV
1431
   case tID:
×
1432
      {
1433
         vlog_node_t v = p_package_identifier();
×
1434
         consume(tSCOPE);
×
UNCOV
1435
         return v;
×
1436
      }
1437
   default:
×
1438
      one_of(tID);
×
UNCOV
1439
      return NULL;
×
1440
   }
1441
}
1442

1443
static vlog_node_t p_primary(void)
124,730✔
1444
{
1445
   // primary_literal | empty_queue
1446
   // | [ class_qualifier | package_scope ] hierarchical_identifier select
1447
   // | concatenation [ [ range_expression ] ]
1448
   // | multiple_concatenation [ [ range_expression ] ]
1449
   // | function_subroutine_call
1450
   // | let_expression | ( mintypmax_expression ) | cast
1451
   // | assignment_pattern_expression | streaming_concatenation
1452
   // | sequence_method_call | this | $ | null
1453

1454
   BEGIN("primary");
249,460✔
1455

1456
   switch (peek()) {
124,730✔
1457
   case tID:
30,804✔
1458
      switch (peek_nth(2)) {
30,804✔
1459
      case tLPAREN:
555✔
1460
      case tATTRBEGIN:
1461
         return p_subroutine_call(V_USER_FCALL);
555✔
1462
      case tSCOPE:
×
UNCOV
1463
         p_package_scope();
×
1464
      default:
30,249✔
1465
         return p_select(p_identifier());
30,249✔
1466
      }
1467
   case tSTRING:
46,922✔
1468
   case tNUMBER:
1469
   case tUNSNUM:
1470
   case tREAL:
1471
      return p_primary_literal();
46,922✔
1472
   case tSYSTASK:
3,061✔
1473
      return p_subroutine_call(V_SYS_FCALL);
3,061✔
1474
   case tLPAREN:
43,592✔
1475
      {
1476
         consume(tLPAREN);
43,592✔
1477
         vlog_node_t expr = p_mintypmax_expression();
43,592✔
1478
         consume(tRPAREN);
43,592✔
1479
         return expr;
43,592✔
1480
      }
1481
   case tLBRACE:
333✔
1482
      {
1483
         consume(tLBRACE);
333✔
1484

1485
         vlog_node_t head = p_expression();
333✔
1486
         if (peek() == tLBRACE)
333✔
1487
            return p_multiple_concatenation(head);
93✔
1488
         else
1489
            return p_concatenation(head);
240✔
1490
      }
1491
   case tNULL:
18✔
1492
      {
1493
         consume(tNULL);
18✔
1494

1495
         vlog_node_t v = vlog_new(V_NULL);
18✔
1496
         vlog_set_loc(v, CURRENT_LOC);
18✔
1497
         return v;
18✔
1498
      }
1499

1500
   default:
×
UNCOV
1501
      one_of(tID, tSTRING, tNUMBER, tUNSNUM, tREAL, tSYSTASK, tLPAREN,
×
1502
             tLBRACE, tNULL);
UNCOV
1503
      return p_select(error_marker());
×
1504
   }
1505
}
1506

1507
static vlog_binary_t p_binary_operator(void)
31,713✔
1508
{
1509
   // + | - | * | / | % | == | != | === | !== | ==? | !=? | && | ||
1510
   //  | ** | < | <= | > | >= | & | | | ^ | ^~ | ~^ | >> | <<
1511
   //  | >>> | <<< | -> | <->
1512

1513
   BEGIN("binary operator");
63,426✔
1514

1515
   switch (one_of(tBAR, tPLUS, tAMP, tCASEEQ, tCASENEQ, tLOGOR,
31,713✔
1516
                  tLOGEQ, tLOGNEQ, tDBLAMP, tSHIFTLL, tSHIFTRL,
1517
                  tSHIFTLA, tSHIFTRA, tLT, tGT, tLE, tGE, tMINUS,
1518
                  tTIMES, tOVER, tPERCENT, tPOWER, tCARET, tTILDECARET,
1519
                  tTILDEAMP, tTILDEBAR)) {
1520
   case tBAR:        return V_BINARY_OR;
1521
   case tAMP:        return V_BINARY_AND;
1,260✔
1522
   case tCASEEQ:     return V_BINARY_CASE_EQ;
1,563✔
1523
   case tCASENEQ:    return V_BINARY_CASE_NEQ;
4,125✔
1524
   case tLOGEQ:      return V_BINARY_LOG_EQ;
1,756✔
1525
   case tLOGNEQ:     return V_BINARY_LOG_NEQ;
1,784✔
1526
   case tLOGOR:      return V_BINARY_LOG_OR;
2,330✔
1527
   case tDBLAMP:     return V_BINARY_LOG_AND;
1,542✔
1528
   case tSHIFTLL:    return V_BINARY_SHIFT_LL;
50✔
1529
   case tSHIFTRL:    return V_BINARY_SHIFT_RL;
49✔
1530
   case tSHIFTLA:    return V_BINARY_SHIFT_LA;
10✔
1531
   case tSHIFTRA:    return V_BINARY_SHIFT_RA;
27✔
1532
   case tLT:         return V_BINARY_LT;
1,385✔
1533
   case tGT:         return V_BINARY_GT;
1,434✔
1534
   case tLE:         return V_BINARY_LEQ;
1,416✔
1535
   case tGE:         return V_BINARY_GEQ;
1,460✔
1536
   case tMINUS:      return V_BINARY_MINUS;
1,782✔
1537
   case tTIMES:      return V_BINARY_TIMES;
1,417✔
1538
   case tOVER:       return V_BINARY_DIVIDE;
1,340✔
1539
   case tPERCENT:    return V_BINARY_MOD;
1,382✔
1540
   case tPOWER:      return V_BINARY_EXP;
17✔
1541
   case tCARET:      return V_BINARY_XOR;
1,219✔
1542
   case tTILDECARET: return V_BINARY_XNOR;
6✔
1543
   case tTILDEAMP:   return V_BINARY_NAND;
16✔
1544
   case tTILDEBAR:   return V_BINARY_NOR;
20✔
1545
   case tPLUS:
2,782✔
1546
   default:          return V_BINARY_PLUS;
2,782✔
1547
   }
1548
}
1549

1550
static vlog_unary_t p_unary_operator(void)
9,328✔
1551
{
1552
   // + | - | ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~
1553

1554
   BEGIN("unary operator");
18,656✔
1555

1556
   switch (one_of(tMINUS, tPLUS, tTILDE, tBANG, tAMP, tBAR, tCARET,
9,328✔
1557
                  tTILDEAMP, tTILDEBAR, tTILDECARET)) {
1558
   case tMINUS:      return V_UNARY_NEG;
1559
   case tTILDE:      return V_UNARY_BITNEG;
1,262✔
1560
   case tBANG:       return V_UNARY_NOT;
1,341✔
1561
   case tAMP:        return V_UNARY_AND;
1,313✔
1562
   case tBAR:        return V_UNARY_OR;
1,233✔
1563
   case tCARET:      return V_UNARY_XOR;
1,177✔
1564
   case tTILDEAMP:   return V_UNARY_NAND;
5✔
1565
   case tTILDEBAR:   return V_UNARY_NOR;
4✔
UNCOV
1566
   case tTILDECARET: return V_UNARY_XNOR;
×
1567
   case tPLUS:
1,330✔
1568
   default:          return V_UNARY_IDENTITY;
1,330✔
1569
   }
1570
}
1571

1572
static vlog_incdec_t p_inc_or_dec_operator(void)
42✔
1573
{
1574
   // ++ | --
1575

1576
   BEGIN("inc or dec operator");
84✔
1577

1578
   switch (one_of(tPLUSPLUS, tMINUSMINUS)) {
42✔
1579
   case tMINUSMINUS: return V_INCDEC_MINUS;
1580
   case tPLUSPLUS:
41✔
1581
   default: return V_INCDEC_PLUS;
41✔
1582
   }
1583
}
1584

1585
static vlog_node_t p_inc_or_dec_expression(vlog_node_t head)
40✔
1586
{
1587
   // inc_or_dec_operator { attribute_instance } variable_lvalue
1588
   //   | variable_lvalue { attribute_instance } inc_or_dec_operator
1589

1590
   BEGIN_WITH_HEAD("inc or dec expression", head);
80✔
1591

1592
   vlog_node_t v = vlog_new(head ? V_POSTFIX : V_PREFIX);
46✔
1593
   vlog_set_subkind(v, p_inc_or_dec_operator());
40✔
1594
   vlog_set_target(v, head ?: p_variable_lvalue());
40✔
1595

1596
   vlog_set_loc(v, CURRENT_LOC);
40✔
1597
   return v;
40✔
1598
}
1599

1600
static vlog_node_t p_nonbinary_expression(void)
124,736✔
1601
{
1602
   // primary | unary_operator { attribute_instance } primary
1603
   //   | inc_or_dec_expression | ( operator_assignment )
1604
   //   | conditional_expression | inside_expression | tagged_union_expression
1605

1606
   switch (peek()) {
124,736✔
1607
   case tID:
115,402✔
1608
   case tSTRING:
1609
   case tNUMBER:
1610
   case tUNSNUM:
1611
   case tREAL:
1612
   case tSYSTASK:
1613
   case tLPAREN:
1614
   case tLBRACE:
1615
   case tNULL:
1616
      return p_primary();
115,402✔
1617
   case tMINUS:
9,328✔
1618
   case tPLUS:
1619
   case tTILDE:
1620
   case tBANG:
1621
   case tAMP:
1622
   case tBAR:
1623
   case tCARET:
1624
   case tTILDEAMP:
1625
   case tTILDEBAR:
1626
   case tTILDECARET:
1627
      {
1628
         vlog_node_t v = vlog_new(V_UNARY);
9,328✔
1629
         vlog_set_subkind(v, p_unary_operator());
9,328✔
1630

1631
         optional_attributes();
9,328✔
1632

1633
         vlog_set_value(v, p_primary());
9,328✔
1634
         vlog_set_loc(v, CURRENT_LOC);
9,328✔
1635
         return v;
9,328✔
1636
      }
1637
   case tPLUSPLUS:
5✔
1638
   case tMINUSMINUS:
1639
      return p_inc_or_dec_expression(NULL);
5✔
1640
   default:
1✔
1641
      one_of(tID, tSTRING, tNUMBER, tUNSNUM, tREAL, tSYSTASK, tLPAREN,
1✔
1642
             tLBRACE, tNULL, tMINUS, tTILDE, tBANG, tAMP, tBAR, tCARET,
1643
             tTILDEAMP, tTILDEBAR, tPLUSPLUS, tTILDECARET, tMINUSMINUS);
1644
      return p_select(error_marker());
1✔
1645
   }
1646
}
1647

1648
static vlog_node_t p_conditional_expression(vlog_node_t head)
1,506✔
1649
{
1650
   // cond_predicate ? { attribute_instance } expression : expression
1651

1652
   BEGIN_WITH_HEAD("conditional expression", head);
3,012✔
1653

1654
   vlog_node_t v = vlog_new(V_COND_EXPR);
1,506✔
1655
   vlog_set_value(v, head);
1,506✔
1656

1657
   consume(tQUESTION);
1,506✔
1658

1659
   optional_attributes();
1,506✔
1660

1661
   vlog_set_left(v, p_expression());
1,506✔
1662

1663
   consume(tCOLON);
1,506✔
1664

1665
   vlog_set_right(v, p_expression());
1,506✔
1666

1667
   vlog_set_loc(v, CURRENT_LOC);
1,506✔
1668
   return v;
1,506✔
1669
}
1670

1671
static bool peek_binary_operator(int *prec)
160,565✔
1672
{
1673
   // See LRM 1800-2017 section 11.3.2 for operator precedence table
1674

1675
   switch (peek()) {
160,565✔
1676
   case tPOWER:      *prec = 12; return true;
21✔
1677
   case tTIMES:
4,163✔
1678
   case tOVER:
1679
   case tPERCENT:    *prec = 11; return true;
4,163✔
1680
   case tPLUS:
4,608✔
1681
   case tMINUS:      *prec = 10; return true;
4,608✔
1682
   case tSHIFTLL:
138✔
1683
   case tSHIFTRL:
1684
   case tSHIFTLA:
1685
   case tSHIFTRA:    *prec = 9;  return true;
138✔
1686
   case tLT:
5,731✔
1687
   case tGT:
1688
   case tLE:
1689
   case tGE:         *prec = 8;  return true;
5,731✔
1690
   case tCASEEQ:
10,484✔
1691
   case tCASENEQ:
1692
   case tLOGEQ:
1693
   case tLOGNEQ:     *prec = 7;  return true;
10,484✔
1694
   case tTILDEAMP:
1,278✔
1695
   case tAMP:        *prec = 6;  return true;
1,278✔
1696
   case tTILDECARET:
1,225✔
1697
   case tCARET:      *prec = 5;  return true;
1,225✔
1698
   case tTILDEBAR:
1,562✔
1699
   case tBAR:        *prec = 4;  return true;
1,562✔
1700
   case tDBLAMP:     *prec = 3;  return true;
1,858✔
1701
   case tLOGOR:      *prec = 2;  return true;
4,795✔
1702
   case tQUESTION:   *prec = 1;  return true;
1,516✔
1703
   default:
1704
      return false;
1705
   }
1706
}
1707

1708
static vlog_node_t p_binary_expression(vlog_node_t lhs, int min_prec)
94,328✔
1709
{
1710
   // Precedence climbing method, see
1711
   //    https://en.wikipedia.org/wiki/Operator-precedence_parser
1712

1713
   int prec1;
94,328✔
1714
   while (peek_binary_operator(&prec1) && prec1 >= min_prec) {
127,547✔
1715
      if (peek() == tQUESTION)
33,219✔
1716
         lhs = p_conditional_expression(lhs);
1,506✔
1717
      else {
1718
         vlog_node_t v = vlog_new(V_BINARY);
31,713✔
1719
         vlog_set_subkind(v, p_binary_operator());
31,713✔
1720
         vlog_set_left(v, lhs);
31,713✔
1721

1722
         optional_attributes();
31,713✔
1723

1724
         vlog_node_t rhs = p_nonbinary_expression();
31,713✔
1725

1726
         int prec2;
31,713✔
1727
         while (peek_binary_operator(&prec2) && prec2 > prec1)
33,018✔
1728
            rhs = p_binary_expression(rhs, prec1 + (prec2 > prec1));
1,305✔
1729

1730
         vlog_set_right(v, rhs);
31,713✔
1731
         vlog_set_loc(v, CURRENT_LOC);
31,713✔
1732
         lhs = v;
31,713✔
1733
      }
1734
   }
1735

1736
   return lhs;
94,328✔
1737
}
1738

1739
static vlog_node_t p_expression(void)
93,023✔
1740
{
1741
   // primary | unary_operator { attribute_instance } primary
1742
   //   | inc_or_dec_expression | ( operator_assignment )
1743
   //   | expression binary_operator { attribute_instance } expression
1744
   //   | conditional_expression | inside_expression | tagged_union_expression
1745

1746
   BEGIN("expression");
186,046✔
1747

1748
   vlog_node_t head = p_nonbinary_expression();
93,023✔
1749
   return p_binary_expression(head, 0);
93,023✔
1750
}
1751

1752
static void p_event_expression(vlog_node_t ctrl)
277✔
1753
{
1754
   // [ edge_identifier ] expression [ iff expression ]
1755
   //   | sequence_instance [ iff expression ]
1756
   //   | event_expression or event_expression
1757
   //   | event_expression , event_expression
1758
   //   | ( event_expression )
1759

1760
   BEGIN("event expression");
554✔
1761

1762
   do {
311✔
1763
      if (optional(tLPAREN)) {
311✔
1764
         p_event_expression(ctrl);
1✔
1765
         consume(tRPAREN);
1✔
1766
      }
1767
      else {
1768
         vlog_node_t v = vlog_new(V_EVENT);
310✔
1769

1770
         if (optional(tPOSEDGE))
310✔
1771
            vlog_set_subkind(v, V_EVENT_POSEDGE);
109✔
1772
         else if (optional(tNEGEDGE))
201✔
1773
            vlog_set_subkind(v, V_EVENT_NEGEDGE);
44✔
1774
         else
1775
            vlog_set_subkind(v, V_EVENT_LEVEL);
157✔
1776

1777
         vlog_set_value(v, p_expression());
310✔
1778
         vlog_set_loc(v, CURRENT_LOC);
310✔
1779

1780
         vlog_add_param(ctrl, v);
310✔
1781
      }
1782
   } while (optional(tOR) || optional(tCOMMA));
311✔
1783
}
277✔
1784

1785
static vlog_node_t p_cond_predicate(void)
2,765✔
1786
{
1787
   // expression_or_cond_pattern { &&& expression_or_cond_pattern }
1788

1789
   BEGIN("cond predicate");
5,530✔
1790

1791
   return p_expression();
2,765✔
1792
}
1793

1794
static vlog_node_t p_event_control(void)
355✔
1795
{
1796
   // @ hierarchical_event_identifier | @ ( event_expression )
1797
   //    | @* | @ (*) | @ ps_or_hierarchical_sequence_identifier
1798

1799
   BEGIN("event control");
710✔
1800

1801
   consume(tAT);
355✔
1802

1803
   vlog_node_t v = vlog_new(V_EVENT_CONTROL);
355✔
1804

1805
   switch (one_of(tLPAREN, tTIMES, tPARENSTAR)) {
355✔
1806
   case tLPAREN:
277✔
1807
      if (peek() == tATTREND)
277✔
1808
         consume(tATTREND);   // Lexing ambiguity
1✔
1809
      else {
1810
         p_event_expression(v);
276✔
1811
         consume(tRPAREN);
276✔
1812
      }
1813
      break;
1814
   case tTIMES:
1815
   case tPARENSTAR:
1816
      break;
1817
   }
1818

1819
   vlog_set_loc(v, CURRENT_LOC);
355✔
1820
   return v;
355✔
1821
}
1822

1823
static vlog_node_t p_delay_value(void)
4,700✔
1824
{
1825
   // unsigned_number | real_number | ps_identifier | time_literal | 1step
1826

1827
   BEGIN("delay value");
9,400✔
1828

1829
   switch (peek()) {
4,700✔
1830
   case tREAL:
5✔
1831
      return p_real_number();
5✔
1832
   case tID:
1✔
1833
      {
1834
         vlog_node_t v = vlog_new(V_REF);
1✔
1835
         vlog_set_ident(v, p_identifier());
1✔
1836
         vlog_set_loc(v, CURRENT_LOC);
1✔
1837

1838
         vlog_symtab_lookup(symtab, v);
1✔
1839
         return v;
1✔
1840
      }
1841
   case tUNSNUM:
4,694✔
1842
   default:
1843
      return p_unsigned_number();
4,694✔
1844
   }
1845
}
1846

1847
static vlog_node_t p_delay_control(void)
4,707✔
1848
{
1849
   // # delay_value | # ( mintypmax_expression )
1850

1851
   BEGIN("delay control");
9,414✔
1852

1853
   consume(tHASH);
4,707✔
1854

1855
   vlog_node_t v = vlog_new(V_DELAY_CONTROL);
4,707✔
1856

1857
   if (peek() != tLPAREN)
4,707✔
1858
      vlog_set_value(v, p_delay_value());
4,695✔
1859
   else
1860
      vlog_set_value(v, p_mintypmax_expression());
12✔
1861

1862
   vlog_set_loc(v, CURRENT_LOC);
4,707✔
1863
   return v;
4,707✔
1864
}
1865

1866
static void p_delay3(void)
7✔
1867
{
1868
   // # delay_value | # ( mintypmax_expression [ , mintypmax_expression
1869
   //   [ , mintypmax_expression ] ] )
1870

1871
   BEGIN("delay3");
14✔
1872

1873
   consume(tHASH);
7✔
1874

1875
   if (peek() != tLPAREN)
7✔
1876
      p_delay_value();
3✔
1877
   else {
1878
      consume(tLPAREN);
4✔
1879

1880
      int expr_cnt = 0;
4✔
1881
      do {
12✔
1882
         (void)p_mintypmax_expression();
12✔
1883
         expr_cnt++;
12✔
1884
      } while (optional(tCOMMA) && (expr_cnt < 3));
12✔
1885

1886
      consume(tRPAREN);
4✔
1887
   }
1888
}
7✔
1889

1890
static void p_delay2(void)
2✔
1891
{
1892
   // # delay_value | # ( mintypmax_expression [ , mintypmax_expression ] )
1893

1894
   BEGIN("delay2");
4✔
1895

1896
   consume(tHASH);
2✔
1897

1898
   if (peek() != tLPAREN)
2✔
1899
      p_delay_value();
1✔
1900
   else {
1901
      consume(tLPAREN);
1✔
1902

1903
      (void)p_mintypmax_expression();
1✔
1904

1905
      if (optional(tCOMMA))
1✔
1906
         (void)p_mintypmax_expression();
1✔
1907

1908
      consume(tRPAREN);
1✔
1909
   }
1910
}
2✔
1911

1912
static vlog_node_t p_delay_or_event_control(void)
66✔
1913
{
1914
   // delay_control | event_control | repeat ( expression ) event_control
1915

1916
   BEGIN("delay or event control");
132✔
1917

1918
   return p_delay_control();
66✔
1919
}
1920

1921
static vlog_node_t p_variable_lvalue(void)
11,875✔
1922
{
1923
   // [ implicit_class_handle . | package_scope ]
1924
   //      hierarchical_variable_identifier select
1925
   //   | { variable_lvalue { , variable_lvalue } }
1926
   //   | [ assignment_pattern_expression_type ]
1927
   //      assignment_pattern_variable_lvalue
1928
   //   | streaming_concatenation
1929

1930
   BEGIN("variable lvalue");
23,750✔
1931

1932
   if (optional(tLBRACE)) {
11,875✔
1933
      vlog_node_t v = vlog_new(V_CONCAT);
41✔
1934

1935
      do {
86✔
1936
         vlog_add_param(v, p_variable_lvalue());
86✔
1937
      } while (optional(tCOMMA));
86✔
1938

1939
      consume(tRBRACE);
41✔
1940

1941
      vlog_set_loc(v, CURRENT_LOC);
41✔
1942
      return v;
41✔
1943
   }
1944
   else {
1945
      ident_t id = p_identifier();
11,834✔
1946
      vlog_node_t v = p_select(id);
11,834✔
1947

1948
      vlog_set_loc(v, CURRENT_LOC);
11,834✔
1949
      return v;
11,834✔
1950
   }
1951
}
1952

1953
static vlog_node_t p_net_lvalue(void)
808✔
1954
{
1955
   // ps_or_hierarchical_net_identifier constant_select
1956
   //   | { net_lvalue { , net_lvalue } }
1957
   //   | [ assignment_pattern_expression_type ] assignment_pattern_net_lvalue
1958

1959
   BEGIN("net lvalue");
1,616✔
1960

1961
   if (optional(tLBRACE)) {
808✔
1962
      vlog_node_t v = vlog_new(V_CONCAT);
11✔
1963

1964
      do {
22✔
1965
         vlog_add_param(v, p_net_lvalue());
22✔
1966
      } while (optional(tCOMMA));
22✔
1967

1968
      consume(tRBRACE);
11✔
1969

1970
      vlog_set_loc(v, CURRENT_LOC);
11✔
1971
      return v;
11✔
1972
   }
1973
   else {
1974
      ident_t id = p_identifier();
797✔
1975
      vlog_node_t v = p_constant_select(id);
797✔
1976

1977
      vlog_set_loc(v, CURRENT_LOC);
797✔
1978
      return v;
797✔
1979
   }
1980
}
1981

1982
static vlog_node_t p_class_new(vlog_node_t dt)
8✔
1983
{
1984
   // [ class_scope ] new [ ( list_of_arguments ) ]
1985
   //    | new expression
1986

1987
   BEGIN("class new");
16✔
1988

1989
   consume(tNEW);
8✔
1990

1991
   if (dt == NULL || vlog_kind(dt) != V_CLASS_DECL) {
8✔
1992
      error_at(&state.last_loc, "new class expression must have class type");
1✔
1993
      dt = NULL;
1✔
1994
   }
1995

1996
   vlog_node_t v = vlog_new(V_CLASS_NEW);
8✔
1997
   vlog_set_type(v, dt);
8✔
1998

1999
   if (optional(tLPAREN)) {
8✔
2000
      p_list_of_arguments(v);
2✔
2001
      consume(tRPAREN);
2✔
2002
   }
2003

2004
   vlog_set_loc(v, CURRENT_LOC);
8✔
2005
   return v;
8✔
2006
}
2007

2008
static vlog_node_t p_dynamic_array_new(vlog_node_t dt)
4✔
2009
{
2010
   // new [ expression ] [ ( expression ) ]
2011

2012
   BEGIN("dynamic array new");
8✔
2013

2014
   consume(tNEW);
4✔
2015
   consume(tLSQUARE);
4✔
2016

2017
   vlog_node_t v = vlog_new(V_DYNAMIC_NEW);
4✔
2018
   vlog_set_type(v, dt);
4✔
2019
   vlog_set_value(v, p_expression());
4✔
2020

2021
   consume(tRSQUARE);
4✔
2022

2023
   if (optional(tLPAREN)) {
4✔
2024
      (void)p_expression();   // TODO: initialise from existing array
×
UNCOV
2025
      consume(tRPAREN);
×
2026
   }
2027

2028
   vlog_set_loc(v, CURRENT_LOC);
4✔
2029
   return v;
4✔
2030
}
2031

2032
static vlog_assign_t p_assignment_operator(void)
193✔
2033
{
2034
   // = | += | -= | *= | /= | %= | &= | |= | ^= | <<= | >>= | <<<= | >>>=
2035

2036
   BEGIN("assignment operator");
386✔
2037

2038
   switch (one_of(tEQ, tPLUSEQ, tMINUSEQ, tTIMESEQ, tDIVEQ, tPERCENTEQ, tAMPEQ,
193✔
2039
                  tBAREQ, tCARETEQ, tLSLEQ, tLSREQ, tASLEQ, tASREQ)) {
2040
   case tPLUSEQ:    return V_ASSIGN_PLUS;
2041
   case tMINUSEQ:   return V_ASSIGN_MINUS;
2042
   case tTIMESEQ:   return V_ASSIGN_TIMES;
2043
   case tDIVEQ:     return V_ASSIGN_DIVIDE;
2044
   case tPERCENTEQ: return V_ASSIGN_MOD;
2045
   case tAMPEQ:     return V_ASSIGN_AND;
2046
   case tBAREQ:     return V_ASSIGN_OR;
2047
   case tCARETEQ:   return V_ASSIGN_XOR;
2048
   case tLSLEQ:     return V_ASSIGN_SHIFT_LL;
2049
   case tLSREQ:     return V_ASSIGN_SHIFT_RL;
2050
   case tASLEQ:     return V_ASSIGN_SHIFT_LA;
2051
   case tASREQ:     return V_ASSIGN_SHIFT_RA;
2052
   default:         return V_ASSIGN_EQUALS;
2053
   }
2054
}
2055

2056
static vlog_node_t p_operator_assignment(vlog_node_t lhs)
193✔
2057
{
2058
   // variable_lvalue assignment_operator expression
2059

2060
   BEGIN_WITH_HEAD("operator assignment", lhs);
386✔
2061

2062
   vlog_node_t v = vlog_new(V_OP_ASSIGN);
193✔
2063
   vlog_set_subkind(v, p_assignment_operator());
193✔
2064
   vlog_set_target(v, lhs);
193✔
2065

2066
   vlog_set_value(v, p_expression());
193✔
2067

2068
   vlog_set_loc(v, CURRENT_LOC);
193✔
2069
   return v;
193✔
2070
}
2071

2072
static vlog_node_t p_blocking_assignment(vlog_node_t lhs)
11,189✔
2073
{
2074
   // variable_lvalue = delay_or_event_control expression
2075
   //   | nonrange_variable_lvalue = dynamic_array_new
2076
   //   | [ implicit_class_handle . | class_scope | package_scope ]
2077
   //         hierarchical_variable_identifier select = class_new
2078
   //   | operator_assignment
2079

2080
   BEGIN_WITH_HEAD("blocking assignment", lhs);
22,378✔
2081

2082
   switch (peek()) {
11,189✔
2083
   case tPLUSEQ:
108✔
2084
   case tMINUSEQ:
2085
   case tTIMESEQ:
2086
   case tDIVEQ:
2087
   case tPERCENTEQ:
2088
   case tAMPEQ:
2089
   case tBAREQ:
2090
   case tCARETEQ:
2091
   case tLSLEQ:
2092
   case tLSREQ:
2093
   case tASLEQ:
2094
   case tASREQ:
2095
      return p_operator_assignment(lhs);
108✔
2096
   }
2097

2098
   consume(tEQ);
11,081✔
2099

2100
   vlog_node_t v = vlog_new(V_BASSIGN);
11,081✔
2101
   vlog_set_target(v, lhs);
11,081✔
2102

2103
   if (peek() == tNEW) {
11,081✔
2104
      if (peek_nth(2) == tLSQUARE)
12✔
2105
         vlog_set_value(v, p_dynamic_array_new(vlog_get_type(lhs)));
4✔
2106
      else
2107
         vlog_set_value(v, p_class_new(vlog_get_type(lhs)));
8✔
2108
   }
2109
   else {
2110
      if (scan(tHASH, tAT))
11,069✔
2111
         vlog_set_delay(v, p_delay_or_event_control());
33✔
2112

2113
      vlog_set_value(v, p_expression());
11,069✔
2114
   }
2115

2116
   vlog_set_loc(v, CURRENT_LOC);
11,081✔
2117
   return v;
11,081✔
2118
}
2119

2120
static vlog_node_t p_nonblocking_assignment(vlog_node_t lhs)
368✔
2121
{
2122
   // variable_lvalue <= [ delay_or_event_control ] expression
2123

2124
   BEGIN_WITH_HEAD("non-blocking assignment", lhs);
736✔
2125

2126
   consume(tLE);
368✔
2127

2128
   vlog_node_t v = vlog_new(V_NBASSIGN);
368✔
2129
   vlog_set_target(v, lhs);
368✔
2130

2131
   if (scan(tHASH, tAT))
368✔
2132
      vlog_set_delay(v, p_delay_or_event_control());
33✔
2133

2134
   vlog_set_value(v, p_expression());
368✔
2135

2136
   vlog_set_loc(v, CURRENT_LOC);
368✔
2137
   return v;
368✔
2138
}
2139

2140
static vlog_node_t p_procedural_timing_control(void)
4,984✔
2141
{
2142
   // delay_control | event_control | cycle_delay
2143

2144
   BEGIN("procedural timing control");
9,968✔
2145

2146
   switch (peek()) {
4,984✔
2147
   case tAT:
355✔
2148
      return p_event_control();
355✔
2149
   case tHASH:
4,629✔
2150
      return p_delay_control();
4,629✔
UNCOV
2151
   default:
×
2152
      should_not_reach_here();
2153
   }
2154
}
2155

2156
static vlog_node_t p_procedural_timing_control_statement(void)
4,984✔
2157
{
2158
   // procedural_timing_control statement_or_null
2159

2160
   BEGIN("procedural timing control statement");
9,968✔
2161

2162
   vlog_node_t v = vlog_new(V_TIMING);
4,984✔
2163
   vlog_set_value(v, p_procedural_timing_control());
4,984✔
2164

2165
   vlog_node_t s = p_statement_or_null();
4,984✔
2166
   if (s != NULL)
4,984✔
2167
      vlog_add_stmt(v, s);
652✔
2168

2169
   vlog_set_loc(v, CURRENT_LOC);
4,984✔
2170
   return v;
4,984✔
2171
}
2172

2173
static vlog_node_t p_seq_block(ident_t id)
2,845✔
2174
{
2175
   // begin [ : block_identifier ] { block_item_declaration }
2176
   //   { statement_or_null } end [ : block_identifier ]
2177

2178
   BEGIN("sequential block");
5,690✔
2179

2180
   consume(tBEGIN);
2,845✔
2181

2182
   vlog_node_t v = vlog_new(V_BLOCK);
2,845✔
2183
   vlog_set_ident(v, id);
2,845✔
2184
   vlog_set_loc(v, CURRENT_LOC);
2,845✔
2185

2186
   vlog_symtab_push(symtab, v);
2,845✔
2187

2188
   if (optional(tCOLON)) {
2,845✔
2189
      ident_t name = p_identifier();
18✔
2190
      if (vlog_has_ident(v))
18✔
2191
         parse_error(&state.last_loc, "cannot specify both a statement label "
1✔
2192
                     "and a block name");
2193
      else
2194
         vlog_set_ident(v, name);
17✔
2195
   }
2196

2197
   skip_over_attributes();
2,845✔
2198

2199
   while (scan_block_item_declaration()) {
2,869✔
2200
      p_block_item_declaration(v);
24✔
2201
      skip_over_attributes();
24✔
2202
   }
2203

2204
   while (not_at_token(tEND)) {
26,756✔
2205
      vlog_node_t s = p_statement_or_null();
23,911✔
2206
      if (s != NULL)
23,911✔
2207
         vlog_add_stmt(v, s);
23,910✔
2208
   }
2209

2210
   vlog_symtab_pop(symtab);
2,845✔
2211

2212
   consume(tEND);
2,845✔
2213

2214
   if (optional(tCOLON)) {
2,845✔
2215
      ident_t name = p_identifier();
6✔
2216
      if (!vlog_has_ident(v))
6✔
2217
         parse_error(&state.last_loc, "initial block does not have a label");
1✔
2218
      else if (name != vlog_ident(v))
5✔
2219
         parse_error(&state.last_loc, "'%s' does not match label '%s'",
1✔
2220
                     istr(name), istr(vlog_ident(v)));
2221
   }
2222

2223
   return v;
2,845✔
2224
}
2225

2226
static vlog_node_t p_par_block(ident_t id)
7✔
2227
{
2228
   // fork [ : block_identifier ] { block_item_declaration }
2229
   //   { statement_or_null } join_keyword [ : block_identifier ]
2230

2231
   BEGIN("parallel block");
14✔
2232

2233
   consume(tFORK);
7✔
2234

2235
   vlog_node_t v = vlog_new(V_FORK);
7✔
2236
   vlog_set_ident(v, id);
7✔
2237
   vlog_set_loc(v, CURRENT_LOC);
7✔
2238

2239
   vlog_symtab_push(symtab, v);
7✔
2240

2241
   if (optional(tCOLON)) {
7✔
2242
      ident_t name = p_identifier();
4✔
2243
      if (vlog_has_ident(v))
4✔
2244
         parse_error(&state.last_loc, "cannot specify both a statement label "
1✔
2245
                     "and a block name");
2246
      else
2247
         vlog_set_ident(v, name);
3✔
2248
   }
2249

2250
   skip_over_attributes();
7✔
2251

2252
   while (scan_block_item_declaration()) {
9✔
2253
      p_block_item_declaration(v);
2✔
2254
      skip_over_attributes();
2✔
2255
   }
2256

2257
   while (not_at_token(tJOIN)) {
14✔
2258
      vlog_node_t s = p_statement_or_null();
7✔
2259
      if (s != NULL)
7✔
2260
         vlog_add_stmt(v, s);
7✔
2261
   }
2262

2263
   vlog_symtab_pop(symtab);
7✔
2264

2265
   consume(tJOIN);
7✔
2266

2267
   if (optional(tCOLON)) {
7✔
2268
      ident_t name = p_identifier();
5✔
2269
      if (!vlog_has_ident(v))
5✔
2270
         parse_error(&state.last_loc, "fork block does not have a label");
1✔
2271
      else if (name != vlog_ident(v))
4✔
2272
         parse_error(&state.last_loc, "'%s' does not match label '%s'",
1✔
2273
                     istr(name), istr(vlog_ident(v)));
2274
   }
2275

2276
   return v;
7✔
2277
}
2278

2279
static vlog_node_t p_subroutine_call_statement(void)
7,231✔
2280
{
2281
   // subroutine_call ; | void ' ( function_subroutine_call ) ;
2282

2283
   BEGIN("subroutine call statement");
14,462✔
2284

2285
   vlog_node_t v;
7,231✔
2286
   switch (peek()) {
7,231✔
2287
   case tSYSTASK:
7,102✔
2288
      v = p_subroutine_call(V_SYS_TCALL);
7,102✔
2289
      break;
7,102✔
2290
   case tVOID:
2✔
2291
      {
2292
         consume(tVOID);
2✔
2293
         consume(tTICK);
2✔
2294
         consume(tLPAREN);
2✔
2295

2296
         const vlog_kind_t kind =
4✔
2297
            peek() == tSYSTASK ? V_SYS_FCALL : V_USER_FCALL;
2✔
2298

2299
         v = vlog_new(V_VOID_CALL);
2✔
2300
         vlog_set_value(v, p_subroutine_call(kind));
2✔
2301

2302
         consume(tRPAREN);
2✔
2303
      }
2304
      break;
2✔
2305
   case tID:
127✔
2306
   default:
2307
      v = p_subroutine_call(V_USER_TCALL);
127✔
2308
      break;
127✔
2309
   }
2310

2311
   consume(tSEMI);
7,231✔
2312

2313
   vlog_set_loc(v, CURRENT_LOC);
7,231✔
2314
   return v;
7,231✔
2315
}
2316

2317
static vlog_node_t p_conditional_statement(void)
2,720✔
2318
{
2319
   // [ unique_priority ] if ( cond_predicate ) statement_or_null
2320
   //     { else if ( cond_predicate ) statement_or_null }
2321
   //     [ else statement_or_null ]
2322

2323
   BEGIN("conditional statement");
5,440✔
2324

2325
   vlog_node_t v = vlog_new(V_IF);
2,720✔
2326

2327
   consume(tIF);
2,720✔
2328
   consume(tLPAREN);
2,720✔
2329

2330
   vlog_node_t c0 = vlog_new(V_COND);
2,720✔
2331
   vlog_set_value(c0, p_cond_predicate());
2,720✔
2332
   vlog_add_cond(v, c0);
2,720✔
2333

2334
   consume(tRPAREN);
2,720✔
2335

2336
   vlog_node_t s0 = p_statement_or_null();
2,720✔
2337
   if (s0 != NULL)
2,720✔
2338
      vlog_add_stmt(c0, s0);
2,709✔
2339

2340
   bool stop = false;
2341
   while (!stop && optional(tELSE)) {
3,199✔
2342
      vlog_node_t c = vlog_new(V_COND);
479✔
2343
      vlog_add_cond(v, c);
479✔
2344

2345
      if (optional(tIF)) {
479✔
2346
         consume(tLPAREN);
45✔
2347
         vlog_set_value(c, p_cond_predicate());
45✔
2348
         consume(tRPAREN);
45✔
2349
      }
2350
      else
2351
         stop = true;
2352

2353
      vlog_node_t s = p_statement_or_null();
479✔
2354
      if (s != NULL)
479✔
2355
         vlog_add_stmt(c, s);
478✔
2356
   }
2357

2358
   vlog_set_loc(v, CURRENT_LOC);
2,720✔
2359
   return v;
2,720✔
2360
}
2361

2362
static vlog_node_t p_variable_assignment(vlog_kind_t kind)
104✔
2363
{
2364
   // variable_lvalue = expression
2365

2366
   BEGIN("variable assignment");
208✔
2367

2368
   vlog_node_t v = vlog_new(kind);
104✔
2369
   vlog_set_target(v, p_variable_lvalue());
104✔
2370

2371
   consume(tEQ);
104✔
2372

2373
   vlog_set_value(v, p_expression());
104✔
2374

2375
   vlog_set_loc(v, CURRENT_LOC);
104✔
2376
   return v;
104✔
2377
}
2378

2379
static void p_list_of_variable_assignments(vlog_node_t parent)
101✔
2380
{
2381
   // variable_assignment { , variable_assignment }
2382

2383
   BEGIN("list of variable assignments");
202✔
2384

2385
   do {
101✔
2386
      vlog_node_t v = p_variable_assignment(V_BASSIGN);
101✔
2387
      vlog_add_stmt(parent, v);
101✔
2388
   } while (optional(tCOMMA));
101✔
2389
}
101✔
2390

2391
static void p_for_variable_declaration(vlog_node_t parent)
7✔
2392
{
2393
   // [ var ] data_type variable_identifier = expression
2394
   //   { , variable_identifier = expression }
2395

2396
   BEGIN("for variable declaration");
14✔
2397

2398
   optional(tVAR);
7✔
2399

2400
   vlog_node_t dt = p_data_type();
7✔
2401

2402
   do {
7✔
2403
      vlog_node_t v = vlog_new(V_LOCAL_DECL);
7✔
2404
      vlog_set_ident(v, p_identifier());
7✔
2405
      vlog_set_type(v, dt);
7✔
2406

2407
      consume(tEQ);
7✔
2408

2409
      vlog_set_value(v, p_expression());
7✔
2410

2411
      vlog_set_loc(v, CURRENT_LOC);
7✔
2412
      vlog_add_decl(parent, v);
7✔
2413

2414
      vlog_symtab_put(symtab, v);
7✔
2415
   } while (optional(tCOMMA));
7✔
2416
}
7✔
2417

2418
static vlog_node_t p_for_initialization(void)
108✔
2419
{
2420
   // list_of_variable_assignments
2421
   //   | for_variable_declaration { , for_variable_declaration }
2422

2423
   BEGIN("for initialization");
216✔
2424

2425
   vlog_node_t v = vlog_new(V_FOR_INIT);
108✔
2426

2427
   if (scan(tREG, tSTRUCT, tUNION, tENUM, tSVINT, tINTEGER, tSVREAL,
108✔
2428
            tSHORTREAL, tREALTIME, tLOGIC, tVAR)) {
2429
      do {
7✔
2430
         p_for_variable_declaration(v);
7✔
2431
      } while (optional(tCOMMA));
7✔
2432
   }
2433
   else
2434
      p_list_of_variable_assignments(v);
101✔
2435

2436
   vlog_set_loc(v, CURRENT_LOC);
108✔
2437
   return v;
108✔
2438
}
2439

2440
static vlog_node_t p_for_step(void)
108✔
2441
{
2442
   // operator_assignment | inc_or_dec_expression | function_subroutine_call
2443

2444
   BEGIN("for step");
216✔
2445

2446
   vlog_node_t v = vlog_new(V_FOR_STEP);
108✔
2447

2448
   switch (peek()) {
108✔
2449
   case tPLUSPLUS:
1✔
2450
   case tMINUSMINUS:
2451
      vlog_add_stmt(v, p_inc_or_dec_expression(NULL));
1✔
2452
      break;
1✔
2453
   default:
107✔
2454
      {
2455
         vlog_node_t head = p_variable_lvalue();
107✔
2456

2457
         switch (peek()) {
107✔
2458
         case tPLUSPLUS:
22✔
2459
         case tMINUSMINUS:
2460
            vlog_add_stmt(v, p_inc_or_dec_expression(head));
22✔
2461
            break;
22✔
2462
         default:
85✔
2463
            vlog_add_stmt(v, p_operator_assignment(head));
85✔
2464
            break;
85✔
2465
         }
2466
      }
2467
      break;
2468
   }
2469

2470
   vlog_set_loc(v, CURRENT_LOC);
108✔
2471
   return v;
108✔
2472
}
2473

2474
static vlog_node_t p_loop_statement(void)
156✔
2475
{
2476
   // forever statement_or_null
2477
   //   | repeat ( expression ) statement_or_null
2478
   //   | while ( expression ) statement_or_null
2479
   //   | for ( [ for_initialization ] ; [ expression ] ; [ for_step ] )
2480
   //       statement_or_null
2481
   //   | do statement_or_null while ( expression ) ;
2482
   //   | foreach ( ps_or_hierarchical_array_identifier [ loop_variables ] )
2483
   //       statement
2484

2485
   BEGIN("loop statement");
312✔
2486

2487
   switch (one_of(tFOREVER, tWHILE, tREPEAT, tDO, tFOR)) {
156✔
2488
   case tFOREVER:
21✔
2489
      {
2490
         vlog_node_t v = vlog_new(V_FOREVER);
21✔
2491

2492
         vlog_node_t s = p_statement_or_null();
21✔
2493
         if (s != NULL)
21✔
2494
            vlog_add_stmt(v, s);
21✔
2495

2496
         vlog_set_loc(v, CURRENT_LOC);
21✔
2497
         return v;
21✔
2498
      }
2499

2500
   case tWHILE:
6✔
2501
      {
2502
         vlog_node_t v = vlog_new(V_WHILE);
6✔
2503

2504
         consume(tLPAREN);
6✔
2505
         vlog_set_value(v, p_expression());
6✔
2506
         consume(tRPAREN);
6✔
2507

2508
         vlog_node_t s = p_statement_or_null();
6✔
2509
         if (s != NULL)
6✔
2510
            vlog_add_stmt(v, s);
4✔
2511

2512
         vlog_set_loc(v, CURRENT_LOC);
6✔
2513
         return v;
6✔
2514
      }
2515

2516
   case tREPEAT:
18✔
2517
      {
2518
         vlog_node_t v = vlog_new(V_REPEAT);
18✔
2519

2520
         consume(tLPAREN);
18✔
2521
         vlog_set_value(v, p_expression());
18✔
2522
         consume(tRPAREN);
18✔
2523

2524
         vlog_node_t s = p_statement_or_null();
18✔
2525
         if (s != NULL)
18✔
2526
            vlog_add_stmt(v, s);
18✔
2527

2528
         vlog_set_loc(v, CURRENT_LOC);
18✔
2529
         return v;
18✔
2530
      }
2531

2532
   case tDO:
2✔
2533
      {
2534
         vlog_node_t v = vlog_new(V_DO_WHILE);
2✔
2535

2536
         vlog_node_t s = p_statement_or_null();
2✔
2537
         if (s != NULL)
2✔
2538
            vlog_add_stmt(v, s);
2✔
2539

2540
         consume(tWHILE);
2✔
2541

2542
         consume(tLPAREN);
2✔
2543
         vlog_set_value(v, p_expression());
2✔
2544
         consume(tRPAREN);
2✔
2545
         consume(tSEMI);
2✔
2546

2547
         vlog_set_loc(v, CURRENT_LOC);
2✔
2548
         return v;
2✔
2549
      }
2550

2551
   case tFOR:
109✔
2552
      {
2553
         vlog_node_t v = vlog_new(V_FOR_LOOP);
109✔
2554

2555
         vlog_symtab_push(symtab, v);
109✔
2556

2557
         consume(tLPAREN);
109✔
2558

2559
         if (not_at_token(tSEMI))
109✔
2560
            vlog_set_left(v, p_for_initialization());
108✔
2561
         else
2562
            vlog_set_left(v, vlog_new(V_FOR_INIT));
1✔
2563

2564
         consume(tSEMI);
109✔
2565

2566
         if (not_at_token(tSEMI))
109✔
2567
            vlog_set_value(v, p_expression());
107✔
2568

2569
         consume(tSEMI);
109✔
2570

2571
         if (not_at_token(tRPAREN))
109✔
2572
            vlog_set_right(v, p_for_step());
108✔
2573
         else
2574
            vlog_set_right(v, vlog_new(V_FOR_STEP));
1✔
2575

2576
         consume(tRPAREN);
109✔
2577

2578
         vlog_node_t s = p_statement_or_null();
109✔
2579
         if (s != NULL)
109✔
2580
            vlog_add_stmt(v, s);
106✔
2581

2582
         vlog_symtab_pop(symtab);
109✔
2583

2584
         vlog_set_loc(v, CURRENT_LOC);
109✔
2585
         return v;
109✔
2586
      }
2587

UNCOV
2588
   default:
×
2589
      should_not_reach_here();
2590
   }
2591
}
2592

2593
static vlog_node_t p_wait_statement(void)
1✔
2594
{
2595
   // wait ( expression ) statement_or_null
2596
   //   | wait fork ;
2597
   //   | wait_order ( hierarchical_identifier { , hierarchical_identifier } )
2598
   //       action_block
2599

2600
   BEGIN("wait statement");
2✔
2601

2602
   consume(tWAIT);
1✔
2603

2604
   vlog_node_t v = vlog_new(V_WAIT);
1✔
2605

2606
   consume(tLPAREN);
1✔
2607

2608
   vlog_set_value(v, p_expression());
1✔
2609

2610
   consume(tRPAREN);
1✔
2611

2612
   vlog_node_t s = p_statement_or_null();
1✔
2613
   if (s != NULL)
1✔
2614
      vlog_add_stmt(v, s);
1✔
2615

2616
   vlog_set_loc(v, CURRENT_LOC);
1✔
2617
   return v;
1✔
2618
}
2619

2620
static vlog_node_t p_case_item(void)
260✔
2621
{
2622
   // case_item_expression { , case_item_expression } : statement_or_null
2623
   //   | default [ : ] statement_or_null
2624

2625
   BEGIN("case item");
520✔
2626

2627
   vlog_node_t v = vlog_new(V_CASE_ITEM);
260✔
2628

2629
   if (optional(tDEFAULT))
260✔
2630
      optional(tCOLON);
59✔
2631
   else {
2632
      do {
205✔
2633
         vlog_add_param(v, p_expression());
205✔
2634
      } while (optional(tCOMMA));
205✔
2635

2636
      consume(tCOLON);
201✔
2637
   }
2638

2639
   vlog_set_loc(v, CURRENT_LOC);
260✔
2640

2641
   vlog_node_t s = p_statement_or_null();
260✔
2642
   if (s != NULL)
260✔
2643
      vlog_add_stmt(v, s);
259✔
2644

2645
   return v;
260✔
2646
}
2647

2648
static vlog_node_t p_case_statement(void)
70✔
2649
{
2650
   // [ unique_priority ] case_keyword ( case_expression )
2651
   //        case_item { case_item } endcase
2652
   //   | [ unique_priority ] case_keyword ( case_expression ) matches
2653
   //        case_pattern_item { case_pattern_item } endcase
2654
   //   | [ unique_priority ] case ( case_expression ) inside case_inside_item
2655
   //        { case_inside_item } endcase
2656

2657
   BEGIN("case statement");
140✔
2658

2659
   vlog_case_kind_t kind = V_CASE_NORMAL;
70✔
2660
   switch (one_of(tCASE, tCASEX, tCASEZ)) {
70✔
2661
   case tCASEX: kind = V_CASE_X; break;
13✔
2662
   case tCASEZ: kind = V_CASE_Z; break;
16✔
2663
   }
2664

2665
   vlog_node_t v = vlog_new(V_CASE);
70✔
2666
   vlog_set_subkind(v, kind);
70✔
2667

2668
   consume(tLPAREN);
70✔
2669

2670
   vlog_set_value(v, p_expression());
70✔
2671

2672
   consume(tRPAREN);
70✔
2673

2674
   do {
260✔
2675
      vlog_add_stmt(v, p_case_item());
260✔
2676
   } while (not_at_token(tENDCASE));
260✔
2677

2678
   consume(tENDCASE);
70✔
2679

2680
   vlog_set_loc(v, CURRENT_LOC);
70✔
2681
   return v;
70✔
2682
}
2683

2684
static vlog_node_t p_event_trigger(void)
1✔
2685
{
2686
   // -> hierarchical_event_identifier ;
2687
   //   | ->> [ delay_or_event_control ] hierarchical_event_identifier ;
2688

2689
   BEGIN("event trigger");
2✔
2690

2691
   consume(tIFIMPL);
1✔
2692

2693
   vlog_node_t v = vlog_new(V_EVENT_TRIGGER);
1✔
2694
   vlog_set_ident(v, p_identifier());
1✔
2695

2696
   consume(tSEMI);
1✔
2697

2698
   vlog_set_loc(v, CURRENT_LOC);
1✔
2699
   return v;
1✔
2700
}
2701

2702
static vlog_node_t p_procedural_continuous_assignment(void)
6✔
2703
{
2704
   // assign variable_assignment | deassign variable_lvalue
2705
   //   | force variable_assignment | force net_assignment
2706
   //   | release variable_lvalue | release net_lvalue
2707

2708
   BEGIN("procedural continuous assignment");
12✔
2709

2710
   switch (one_of(tASSIGN, tDEASSIGN, tFORCE, tRELEASE)) {
6✔
2711
   case tASSIGN:
1✔
2712
   default:
2713
      return p_variable_assignment(V_ASSIGN);
1✔
2714
   case tDEASSIGN:
1✔
2715
      {
2716
         vlog_node_t v = vlog_new(V_DEASSIGN);
1✔
2717
         vlog_set_target(v, p_variable_lvalue());
1✔
2718
         vlog_set_loc(v, CURRENT_LOC);
1✔
2719
         return v;
1✔
2720
      }
2721
   case tFORCE:
2✔
2722
      return p_variable_assignment(V_FORCE);
2✔
2723
   case tRELEASE:
2✔
2724
      {
2725
         vlog_node_t v = vlog_new(V_RELEASE);
2✔
2726
         vlog_set_target(v, p_variable_lvalue());
2✔
2727
         vlog_set_loc(v, CURRENT_LOC);
2✔
2728
         return v;
2✔
2729
      }
2730
   }
2731
}
2732

2733
static vlog_node_t p_disable_statement(void)
1✔
2734
{
2735
   // disable hierarchical_task_identifier ;
2736
   //   | disable hierarchical_block_identifier ;
2737
   //   | disable fork ;
2738

2739
   BEGIN("disable statement");
2✔
2740

2741
   consume(tDISABLE);
1✔
2742

2743
   vlog_node_t v = vlog_new(V_DISABLE);
1✔
2744
   vlog_set_ident(v, p_identifier());
1✔
2745

2746
   consume(tSEMI);
1✔
2747

2748
   vlog_set_loc(v, CURRENT_LOC);
1✔
2749
   return v;
1✔
2750
}
2751

2752
static vlog_node_t p_jump_statement(void)
7✔
2753
{
2754
   // return [ expression ] ; | break ; | continue ;
2755

2756
   BEGIN("jump statement");
14✔
2757

2758
   switch (one_of(tRETURN)) {
7✔
2759
   case tRETURN:
7✔
2760
      {
2761
         vlog_node_t v = vlog_new(V_RETURN);
7✔
2762

2763
         vlog_node_t subr = vlog_symtab_subr(symtab);
7✔
2764
         if (subr == NULL)
7✔
2765
            parse_error(&state.last_loc, "return statement can only be used "
1✔
2766
                        "in a subroutine");
2767
         else
2768
            vlog_set_ref(v, subr);
6✔
2769

2770
         if (peek() != tSEMI)
7✔
2771
            vlog_set_value(v, p_expression());
5✔
2772

2773
         consume(tSEMI);
7✔
2774

2775
         vlog_set_loc(v, CURRENT_LOC);
7✔
2776
         return v;
14✔
2777
      }
UNCOV
2778
   default:
×
2779
      should_not_reach_here();
2780
   }
2781
}
2782

2783
static vlog_node_t p_statement_item(ident_t id)
29,600✔
2784
{
2785
   // blocking_assignment ; | nonblocking_assignment ;
2786
   //   | procedural_continuous_assignment ; | case_statement
2787
   //   | conditional_statement | inc_or_dec_expression ;
2788
   //   | subroutine_call_statement | disable_statement
2789
   //   | event_trigger | loop_statement | jump_statement
2790
   //   | par_block | procedural_timing_control_statement
2791
   //   | seq_block | wait_statement | procedural_assertion_statement
2792
   //   | clocking_drive ; | randsequence_statement | randcase_statement
2793
   //   | expect_property_statement
2794

2795
   BEGIN("statement item");
59,200✔
2796

2797
   switch (peek()) {
29,600✔
2798
   case tID:
11,655✔
2799
      switch (peek_nth(2)) {
11,655✔
2800
      case tLPAREN:
127✔
2801
      case tSEMI:
2802
      case tATTRBEGIN:
2803
         return p_subroutine_call_statement();
127✔
2804
      default:
11,528✔
2805
         {
2806
            vlog_node_t lhs = p_variable_lvalue(), v;
11,528✔
2807

2808
            switch (peek()) {
11,528✔
2809
            case tLE:
364✔
2810
               v = p_nonblocking_assignment(lhs);
364✔
2811
               break;
364✔
2812
            case tPLUSPLUS:
12✔
2813
            case tMINUSMINUS:
2814
               v = p_inc_or_dec_expression(lhs);
12✔
2815
               break;
12✔
2816
            default:
11,152✔
2817
               v = p_blocking_assignment(lhs);
11,152✔
2818
               break;
11,152✔
2819
            }
2820

2821
            consume(tSEMI);
11,528✔
2822
            return v;
11,528✔
2823
         }
2824
      }
2825
   case tLBRACE:
41✔
2826
      {
2827
         vlog_node_t lhs = p_variable_lvalue(), v;
41✔
2828

2829
         if (peek() == tLE)
41✔
2830
            v = p_nonblocking_assignment(lhs);
4✔
2831
         else
2832
            v = p_blocking_assignment(lhs);
37✔
2833

2834
         consume(tSEMI);
41✔
2835
         return v;
41✔
2836
      }
2837
   case tDISABLE:
1✔
2838
      return p_disable_statement();
1✔
2839
   case tAT:
4,984✔
2840
   case tHASH:
2841
      return p_procedural_timing_control_statement();
4,984✔
2842
   case tBEGIN:
2,845✔
2843
      return p_seq_block(id);
2,845✔
2844
   case tFORK:
7✔
2845
      return p_par_block(id);
7✔
2846
   case tSYSTASK:
7,104✔
2847
   case tVOID:
2848
      return p_subroutine_call_statement();
7,104✔
2849
   case tIF:
2,720✔
2850
      return p_conditional_statement();
2,720✔
2851
   case tFOREVER:
156✔
2852
   case tWHILE:
2853
   case tREPEAT:
2854
   case tDO:
2855
   case tFOR:
2856
      return p_loop_statement();
156✔
2857
   case tWAIT:
1✔
2858
      return p_wait_statement();
1✔
2859
   case tCASE:
70✔
2860
   case tCASEX:
2861
   case tCASEZ:
2862
      return p_case_statement();
70✔
2863
   case tIFIMPL:
1✔
2864
      return p_event_trigger();
1✔
2865
   case tASSIGN:
6✔
2866
   case tDEASSIGN:
2867
   case tFORCE:
2868
   case tRELEASE:
2869
      {
2870
         vlog_node_t v = p_procedural_continuous_assignment();
6✔
2871
         consume(tSEMI);
6✔
2872
         return v;
6✔
2873
      }
2874
   case tRETURN:
7✔
2875
      return p_jump_statement();
7✔
2876
   default:
2✔
2877
      one_of(tID, tAT, tHASH, tBEGIN, tFORK, tSYSTASK, tVOID, tIF, tFOREVER,
2✔
2878
             tWHILE, tREPEAT, tDO, tFOR, tWAIT, tCASE, tCASEX, tCASEZ, tIFIMPL,
2879
             tASSIGN, tDEASSIGN, tFORCE, tRELEASE, tRETURN);
2880
      drop_tokens_until(&state, tSEMI);
2✔
2881
      return vlog_new(V_BLOCK);  // Dummy statement
2✔
2882
   }
2883
}
2884

2885
static vlog_node_t p_statement(void)
29,600✔
2886
{
2887
   // [ block_identifier : ] { attribute_instance } statement_item
2888

2889
   BEGIN("statement");
59,200✔
2890

2891
   ident_t id = NULL;
29,600✔
2892
   if (peek() == tID && peek_nth(2) == tCOLON) {
29,600✔
2893
      id = p_identifier();
6✔
2894
      consume(tCOLON);
6✔
2895
   }
2896

2897
   optional_attributes();
29,600✔
2898

2899
   return p_statement_item(id);
29,600✔
2900
}
2901

2902
static vlog_node_t p_statement_or_null(void)
33,625✔
2903
{
2904
   // statement | { attribute_instance } ;
2905

2906
   BEGIN("statement or null");
67,250✔
2907

2908
   if (optional(tSEMI))
33,625✔
2909
      return NULL;
2910
   else
2911
      return p_statement();
29,273✔
2912
}
2913

2914
static vlog_node_t p_always_construct(void)
326✔
2915
{
2916
   // always_keyword statement
2917

2918
   BEGIN("always construct");
652✔
2919

2920
   vlog_node_t v = vlog_new(V_ALWAYS);
326✔
2921

2922
   switch (one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH)) {
326✔
2923
   case tALWAYSCOMB:  vlog_set_subkind(v, V_ALWAYS_COMB);  break;
1✔
2924
   case tALWAYSFF:    vlog_set_subkind(v, V_ALWAYS_FF);    break;
1✔
2925
   case tALWAYSLATCH: vlog_set_subkind(v, V_ALWAYS_LATCH); break;
5✔
2926
   default:           vlog_set_subkind(v, V_ALWAYS_PLAIN); break;
319✔
2927
   }
2928

2929
   vlog_set_ident(v, default_label("always"));
326✔
2930
   vlog_add_stmt(v, p_statement());
326✔
2931

2932
   vlog_set_loc(v, CURRENT_LOC);
326✔
2933
   return v;
326✔
2934
}
2935

2936
static vlog_node_t p_final_construct(void)
1✔
2937
{
2938
   // final function_statement
2939

2940
   BEGIN("final construct");
2✔
2941

2942
   consume(tFINAL);
1✔
2943

2944
   vlog_node_t v = vlog_new(V_FINAL);
1✔
2945
   vlog_set_ident(v, default_label("final"));
1✔
2946
   vlog_add_stmt(v, p_statement());
1✔
2947

2948
   vlog_set_loc(v, CURRENT_LOC);
1✔
2949
   return v;
1✔
2950
}
2951

2952
static vlog_node_t p_initial_construct(void)
868✔
2953
{
2954
   // initial statement_or_null
2955

2956
   BEGIN("initial construct");
1,736✔
2957

2958
   consume(tINITIAL);
868✔
2959

2960
   vlog_node_t v = vlog_new(V_INITIAL);
868✔
2961
   vlog_set_ident(v, default_label("initial"));
868✔
2962

2963
   vlog_node_t s = p_statement_or_null();
868✔
2964
   if (s != NULL)
868✔
2965
      vlog_add_stmt(v, s);
868✔
2966

2967
   vlog_set_loc(v, CURRENT_LOC);
868✔
2968
   return v;
868✔
2969
}
2970

2971
static vlog_node_t p_net_assignment(vlog_node_t delay, vlog_node_t strength)
696✔
2972
{
2973
   // net_lvalue = expression
2974

2975
   BEGIN("net assignment");
1,392✔
2976

2977
   vlog_symtab_set_implicit(symtab, implicit_kind);
696✔
2978

2979
   vlog_node_t v = vlog_new(V_ASSIGN);
696✔
2980
   vlog_set_target(v, p_net_lvalue());
696✔
2981
   vlog_set_ident(v, default_label("assign"));
696✔
2982
   vlog_set_delay(v, delay);
696✔
2983
   if (strength != NULL)
696✔
2984
      vlog_add_param(v, strength);
55✔
2985

2986
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
696✔
2987

2988
   consume(tEQ);
696✔
2989

2990
   vlog_set_value(v, p_expression());
696✔
2991

2992
   vlog_set_loc(v, CURRENT_LOC);
696✔
2993
   return v;
696✔
2994
}
2995

2996
static void p_list_of_net_assignments(vlog_node_t mod, vlog_node_t delay,
696✔
2997
                                      vlog_node_t strength)
2998
{
2999
   // net_assignment { , net_assignment }
3000

3001
   BEGIN("list of net assignments");
1,392✔
3002

3003
   do {
696✔
3004
      vlog_add_stmt(mod, p_net_assignment(delay, strength));
696✔
3005
   } while (optional(tCOMMA));
696✔
3006
}
696✔
3007

3008
static void p_continuous_assign(vlog_node_t mod)
696✔
3009
{
3010
   // assign [ drive_strength ] [ delay3 ] list_of_net_assignments ;
3011
   //   | assign [ delay_control ] list_of_variable_assignments ;
3012

3013
   BEGIN("continuous assignment");
1,392✔
3014

3015
   consume(tASSIGN);
696✔
3016

3017
   vlog_node_t delay = NULL;
696✔
3018
   vlog_node_t strength = NULL;
696✔
3019
   if (peek() == tLPAREN) {
696✔
3020
      strength = p_drive_strength();
55✔
3021
      if (peek() == tHASH)
55✔
3022
         p_delay3();
2✔
3023
   } else if (peek() == tHASH)
641✔
3024
      delay = p_delay_control();
12✔
3025

3026
   p_list_of_net_assignments(mod, delay, strength);
696✔
3027

3028
   consume(tSEMI);
696✔
3029
}
696✔
3030

3031
static vlog_net_kind_t p_net_type(void)
1,031✔
3032
{
3033
   // supply0 | supply1 | tri | triand | trior | trireg | tri0
3034
   //   | tri1 | uwire | wire | wand | wor
3035

3036
   BEGIN("net type");
2,062✔
3037

3038
   switch (one_of(tWIRE, tUWIRE, tSUPPLY0, tSUPPLY1, tTRI, tTRIAND,
1,031✔
3039
                  tTRIOR, tTRIREG, tTRI0, tTRI1, tWAND, tWOR)) {
3040
   case tSUPPLY0: return V_NET_SUPPLY0;
3041
   case tSUPPLY1: return V_NET_SUPPLY1;
4✔
3042
   case tTRI:     return V_NET_TRI;
1✔
3043
   case tTRIAND:  return V_NET_TRIAND;
2✔
3044
   case tTRIOR:   return V_NET_TRIOR;
2✔
3045
   case tTRIREG:  return V_NET_TRIREG;
1✔
3046
   case tTRI0:    return V_NET_TRI0;
4✔
3047
   case tTRI1:    return V_NET_TRI1;
2✔
3048
   case tUWIRE:   return V_NET_UWIRE;
1✔
3049
   case tWAND:    return V_NET_WAND;
1✔
3050
   case tWOR:     return V_NET_WOR;
1✔
3051
   case tWIRE:
1,004✔
3052
   default:       return V_NET_WIRE;
1,004✔
3053
   }
3054
}
3055

3056
static vlog_node_t p_net_decl_assignment(vlog_net_kind_t kind,
1,054✔
3057
                                         vlog_node_t datatype)
3058
{
3059
   // net_identifier { unpacked_dimension } [ = expression ]
3060

3061
   BEGIN("net declaration assignment");
2,108✔
3062

3063
   vlog_node_t v = vlog_new(V_NET_DECL);
1,054✔
3064
   vlog_set_subkind(v, kind);
1,054✔
3065
   vlog_set_type(v, datatype);
1,054✔
3066
   vlog_set_ident(v, p_identifier());
1,054✔
3067

3068
   while (peek() == tLSQUARE)
1,068✔
3069
      vlog_add_range(v, p_unpacked_dimension());
14✔
3070

3071
   if (optional(tEQ))
1,054✔
3072
      vlog_set_value(v, p_expression());
401✔
3073

3074
   vlog_set_loc(v, CURRENT_LOC);
1,054✔
3075
   vlog_symtab_put(symtab, v);
1,054✔
3076
   return v;
1,054✔
3077
}
3078

3079
static void p_list_of_net_decl_assignments(vlog_node_t mod,
945✔
3080
                                           vlog_net_kind_t kind,
3081
                                           vlog_node_t datatype)
3082
{
3083
   // net_decl_assignment { , net_decl_assignment }
3084

3085
   BEGIN("list of net declaration assignments");
1,890✔
3086

3087
   do {
1,054✔
3088
      vlog_node_t v = p_net_decl_assignment(kind, datatype);
1,054✔
3089
      vlog_add_decl(mod, v);
1,054✔
3090
   } while (optional(tCOMMA));
1,054✔
3091
}
945✔
3092

3093
static vlog_node_t p_drive_strength(void)
59✔
3094
{
3095
   //( strength0 , strength1 ) | ( strength1 , strength0 )
3096
   //| ( strength0 , highz1 )  | ( strength1 , highz0 )
3097
   //| ( highz0 , strength1 )  | ( highz1 , strength0 )
3098

3099
   BEGIN("drive strength");
118✔
3100

3101
   consume(tLPAREN);
59✔
3102

3103
   vlog_strength_t s0, s1;
59✔
3104
   switch (peek()) {
59✔
3105
   case tSUPPLY0:
9✔
3106
   case tSTRONG0:
3107
   case tPULL0:
3108
   case tWEAK0:
3109
      {
3110
         s0 = p_strength0();
9✔
3111
         consume(tCOMMA);
9✔
3112
         if (optional(tHIGHZ1))
9✔
3113
            s1 = V_STRENGTH_HIGHZ;
3114
         else
3115
            s1 = p_strength1();
8✔
3116
      }
3117
      break;
3118
   case tHIGHZ0:
1✔
3119
      {
3120
         s0 = V_STRENGTH_HIGHZ;
1✔
3121
         consume(tHIGHZ0);
1✔
3122
         consume(tCOMMA);
1✔
3123
         s1 = p_strength1();
1✔
3124
      }
3125
      break;
1✔
3126
   case tSUPPLY1:
48✔
3127
   case tSTRONG1:
3128
   case tPULL1:
3129
   case tWEAK1:
3130
      {
3131
         s1 = p_strength1();
48✔
3132
         consume(tCOMMA);
48✔
3133
         if (optional(tHIGHZ0))
48✔
3134
            s0 = V_STRENGTH_HIGHZ;
3135
         else
3136
            s0 = p_strength0();
48✔
3137
      }
3138
      break;
3139
   case tHIGHZ1:
1✔
3140
      {
3141
         s1 = V_STRENGTH_HIGHZ;
1✔
3142
         consume(tHIGHZ1);
1✔
3143
         consume(tCOMMA);
1✔
3144
         s0 = p_strength0();
1✔
3145
      }
3146
      break;
1✔
UNCOV
3147
   default:
×
3148
      should_not_reach_here();
3149
   }
3150

3151
   consume(tRPAREN);
59✔
3152

3153
   vlog_node_t v = vlog_new(V_STRENGTH);
59✔
3154
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
59✔
3155
   vlog_set_loc(v, CURRENT_LOC);
59✔
3156

3157
   return v;
59✔
3158
}
3159

3160
static vlog_strength_t p_charge_strength(void)
2✔
3161
{
3162
   // ( small ) | ( medium ) | ( large )
3163

3164
   BEGIN("drive charge");
4✔
3165

3166
   consume(tLPAREN);
2✔
3167

3168
   vlog_strength_t s;
2✔
3169
   switch (one_of(tSMALL, tMEDIUM, tLARGE)) {
2✔
3170
   default:
3171
   case tSMALL:  s = V_STRENGTH_SMALL;
3172
   case tMEDIUM: s = V_STRENGTH_MEDIUM;
2✔
3173
   case tLARGE:  s = V_STRENGTH_LARGE;
2✔
3174
   }
3175

3176
   consume(tRPAREN);
2✔
3177

3178
   return s;
2✔
3179
}
3180

3181
static void p_net_declaration(vlog_node_t mod)
946✔
3182
{
3183
   // net_type [ drive_strength | charge_strength ] [ vectored | scalared ]
3184
   //     data_type_or_implicit [ delay3 ] list_of_net_decl_assignments ;
3185
   //  | net_type_identifier [ delay_control ] list_of_net_decl_assignments ;
3186
   //  | interconnect implicit_data_type [ # delay_value ] net_identifier
3187
   //     { unpacked_dimension } [ , net_identifier { unpacked_dimension } ] ;
3188

3189
   BEGIN("net declaration");
1,892✔
3190

3191
   ident_t id;
946✔
3192
   vlog_node_t dt;
946✔
3193
   vlog_net_kind_t kind = V_NET_WIRE;
946✔
3194

3195
   switch (peek()) {
946✔
3196
   case tINTERCONNECT:
1✔
3197
      {
3198
         consume(tINTERCONNECT);
1✔
3199

3200
         dt = p_implicit_data_type();
1✔
3201

3202
         if (optional(tHASH))
1✔
3203
            p_delay_value();
1✔
3204

3205
         do {
1✔
3206
            id = p_identifier();
1✔
3207
            if (peek() == tLSQUARE)
1✔
3208
               p_unpacked_dimension();
1✔
3209
         } while (optional(tCOMMA));
1✔
3210
      }
3211
      break;
3212

UNCOV
3213
   case tID:
×
3214
      {
3215
         id = p_identifier();
×
3216
         dt = vlog_symtab_query(symtab, id);
×
UNCOV
3217
         if (dt == NULL)
×
3218
            should_not_reach_here();
3219
         // TODO check that the identifier is actually
3220
         // a user declared nettype
3221

3222
         if (peek() == tHASH)
×
UNCOV
3223
            p_delay_control();
×
3224

UNCOV
3225
         p_list_of_net_decl_assignments(mod, kind, dt);
×
3226
      }
UNCOV
3227
      break;
×
3228

3229
   default:
945✔
3230
      {
3231
         kind = p_net_type();
945✔
3232

3233
         if (peek() == tLPAREN) {
945✔
3234
            switch (peek_nth(2)) {
4✔
3235
            case tHIGHZ0:
2✔
3236
            case tHIGHZ1:
3237
            case tSUPPLY0:
3238
            case tSUPPLY1:
3239
            case tSTRONG0:
3240
            case tSTRONG1:
3241
            case tPULL0:
3242
            case tPULL1:
3243
            case tWEAK0:
3244
            case tWEAK1:
3245
               p_drive_strength();
2✔
3246
               break;
2✔
3247
            case tSMALL:
2✔
3248
            case tMEDIUM:
3249
            case tLARGE:
3250
               if (kind != V_NET_TRIREG)
2✔
3251
                  parse_error(&state.last_loc, "charge strength only allowed "
1✔
3252
                              "with the trireg keyword");
3253
               p_charge_strength();
2✔
3254
               break;
2✔
3255
            default:
×
UNCOV
3256
               one_of(tHIGHZ0, tHIGHZ1, tSUPPLY0, tSUPPLY1, tSTRONG0, tSTRONG1,
×
3257
                     tPULL0, tPULL1, tWEAK0, tWEAK1, tSMALL, tMEDIUM, tLARGE);
3258
               drop_tokens_until(&state, tSEMI);
×
UNCOV
3259
               return;
×
3260
            }
3261
         }
3262

3263
         bool need_packed = false;
945✔
3264
         if (optional(tVECTORED) || optional(tSCALARED))
945✔
3265
            need_packed = true;
3266

3267
         dt = p_data_type_or_implicit();
945✔
3268

3269
         if (need_packed) {
945✔
3270
            bool has_packed = false;
2✔
3271
            unsigned ranges = vlog_ranges(dt);
2✔
3272
            for (unsigned i = 0; i < ranges; i++) {
3✔
3273
               vlog_node_t r = vlog_range(dt, i);
1✔
3274
               if (vlog_subkind(r) == V_DIM_PACKED)
1✔
3275
                  has_packed |= true;
1✔
3276
            }
3277
            if (!has_packed)
2✔
3278
               parse_error(&state.last_loc, "vectored and scalared keywords "
1✔
3279
                           "are only allowed with at least a packed dimension");
3280
         }
3281

3282
         if (peek() == tHASH)
945✔
3283
            p_delay3();
5✔
3284

3285
         p_list_of_net_decl_assignments(mod, kind, dt);
945✔
3286
      }
3287
   }
3288

3289
   consume(tSEMI);
946✔
3290
}
3291

3292
static vlog_node_t p_unsized_dimension(void)
5✔
3293
{
3294
   // [ ]
3295

3296
   BEGIN("unsized dimension");
10✔
3297

3298
   consume(tLSQUARE);
5✔
3299
   consume(tRSQUARE);
5✔
3300

3301
   vlog_node_t v = vlog_new(V_DIMENSION);
5✔
3302
   vlog_set_subkind(v, V_DIM_UNSIZED);
5✔
3303
   vlog_set_loc(v, CURRENT_LOC);
5✔
3304

3305
   return v;
5✔
3306
}
3307

3308
static vlog_node_t p_variable_dimension(void)
103✔
3309
{
3310
   // unsized_dimension | unpacked_dimension | associative_dimension
3311
   //   | queue_dimension
3312

3313
   BEGIN("variable dimension");
206✔
3314

3315
   switch (peek_nth(2)) {
103✔
3316
   case tRSQUARE:
5✔
3317
      return p_unsized_dimension();
5✔
3318
   default:
98✔
3319
      return p_unpacked_dimension();
98✔
3320
   }
3321
}
3322

3323
static vlog_node_t p_variable_decl_assignment(vlog_node_t datatype,
4,578✔
3324
                                              vlog_kind_t kind)
3325
{
3326
   // variable_identifier { variable_dimension } [ = expression ]
3327
   //   | dynamic_array_variable_identifier unsized_dimension
3328
   //       { variable_dimension } [ = dynamic_array_new ]
3329
   //   | class_variable_identifier [ = class_new ]
3330

3331
   BEGIN("variable declaration assignment");
9,156✔
3332

3333
   vlog_node_t v = vlog_new(kind);
4,578✔
3334
   vlog_set_ident(v, p_identifier());
4,578✔
3335
   vlog_set_type(v, datatype);
4,578✔
3336

3337
   while (peek() == tLSQUARE)
4,681✔
3338
      vlog_add_range(v, p_variable_dimension());
103✔
3339

3340
   if (optional(tEQ))
4,578✔
3341
      vlog_set_value(v, p_expression());
275✔
3342

3343
   vlog_set_loc(v, CURRENT_LOC);
4,578✔
3344
   vlog_symtab_put(symtab, v);
4,578✔
3345
   return v;
4,578✔
3346
}
3347

3348
static void p_list_of_variable_decl_assignments(vlog_node_t parent,
3,934✔
3349
                                                vlog_node_t datatype,
3350
                                                vlog_kind_t kind)
3351
{
3352
   // variable_decl_assignment { , variable_decl_assignment }
3353

3354
   BEGIN("list of variable declaration assignments");
7,868✔
3355

3356
   do {
4,578✔
3357
      vlog_add_decl(parent, p_variable_decl_assignment(datatype, kind));
4,578✔
3358
   } while (optional(tCOMMA));
4,578✔
3359
}
3,934✔
3360

3361
static vlog_node_t p_type_declaration(void)
33✔
3362
{
3363
   // typedef data_type type_identifier { variable_dimension } ;
3364
   //   | typedef interface_instance_identifier constant_bit_select .
3365
   //       type_identifier type_identifier ;
3366
   //   | typedef [ enum | struct | union | class | interface class ]
3367
   //       type_identifier ;
3368

3369
   BEGIN("type declaration");
66✔
3370

3371
   consume(tTYPEDEF);
33✔
3372

3373
   vlog_node_t v = vlog_new(V_TYPE_DECL);
33✔
3374
   vlog_set_type(v, p_data_type());
33✔
3375
   vlog_set_ident(v, p_identifier());
33✔
3376

3377
   consume(tSEMI);
33✔
3378

3379
   vlog_set_loc(v, CURRENT_LOC);
33✔
3380
   vlog_symtab_put(symtab, v);
33✔
3381
   return v;
33✔
3382
}
3383

3384
static vlog_node_t p_package_import_item(void)
3✔
3385
{
3386
   // package_identifier :: identifier | package_identifier :: *
3387

3388
   BEGIN("package import item");
6✔
3389

3390
   vlog_node_t pack = p_package_identifier();
3✔
3391

3392
   vlog_node_t v = vlog_new(V_IMPORT_DECL);
3✔
3393
   vlog_set_ref(v, pack);
3✔
3394

3395
   consume(tSCOPE);
3✔
3396

3397
   if (peek() == tID)
3✔
3398
      vlog_set_ident(v, p_identifier());
1✔
3399
   else
3400
      one_of(tTIMES, tID);
2✔
3401

3402
   vlog_set_loc(v, CURRENT_LOC);
3✔
3403
   vlog_symtab_import(symtab, v);
3✔
3404
   return v;
3✔
3405
}
3406

3407
static void p_package_import_declaration(vlog_node_t parent)
3✔
3408
{
3409
   // import package_import_item { , package_import_item } ;
3410

3411
   BEGIN("package import declaration");
6✔
3412

3413
   consume(tIMPORT);
3✔
3414

3415
   do {
3✔
3416
      vlog_add_decl(parent, p_package_import_item());
3✔
3417
   } while (optional(tCOMMA));
3✔
3418

3419
   consume(tSEMI);
3✔
3420
}
3✔
3421

3422
static void p_data_declaration(vlog_node_t parent, vlog_kind_t kind)
3,894✔
3423
{
3424
   // [ const ] [ var ] [ lifetime ] data_type_or_implicit
3425
   //     list_of_variable_decl_assignments ;
3426
   //  | type_declaration | package_import_declaration | net_type_declaration
3427

3428
   BEGIN("data declaration");
7,788✔
3429

3430
   switch (peek()) {
3,894✔
3431
   case tTYPEDEF:
33✔
3432
      vlog_add_decl(parent, p_type_declaration());
33✔
3433
      break;
33✔
3434
   case tIMPORT:
3✔
3435
      p_package_import_declaration(parent);
3✔
3436
      break;
3✔
3437
   default:
3,858✔
3438
      {
3439
         optional(tVAR);
3,858✔
3440

3441
         vlog_node_t dt = p_data_type_or_implicit();
3,858✔
3442
         p_list_of_variable_decl_assignments(parent, dt, kind);
3,858✔
3443

3444
         consume(tSEMI);
3,858✔
3445
      }
3446
   }
3447
}
3,894✔
3448

3449
static v_port_kind_t p_port_direction(void)
231✔
3450
{
3451
   // input | output | inout | ref
3452

3453
   BEGIN("port direction");
462✔
3454

3455
   switch (one_of(tINPUT, tOUTPUT, tINOUT)) {
231✔
3456
   case tINPUT:  return V_PORT_INPUT;
3457
   case tOUTPUT: return V_PORT_OUTPUT;
4✔
3458
   case tINOUT:  return V_PORT_INOUT;
1✔
3459
   default:      return V_PORT_INPUT;
3460
   }
3461
}
3462

3463
static v_port_kind_t p_tf_port_direction(void)
231✔
3464
{
3465
   // port_direction | const ref
3466

3467
   BEGIN("task or function port direction");
462✔
3468

3469
   return p_port_direction();
231✔
3470
}
3471

3472
static vlog_node_t p_tf_port_item(void)
155✔
3473
{
3474
   // { attribute_instance } [ tf_port_direction ] [ var ]
3475
   //    data_type_or_implicit [ port_identifier { variable_dimension }
3476
   //    [ = expression ] ]
3477

3478
   BEGIN("task or function port item");
310✔
3479

3480
   vlog_node_t v = vlog_new(V_TF_PORT_DECL);
155✔
3481

3482
   skip_over_attributes();
155✔
3483

3484
   if (scan(tINPUT, tOUTPUT, tINOUT))
155✔
3485
      vlog_set_subkind(v, p_tf_port_direction());
132✔
3486
   else
3487
      vlog_set_subkind(v, V_PORT_INPUT);
23✔
3488

3489
   vlog_set_type(v, p_data_type_or_implicit());
155✔
3490

3491
   if (peek() == tID) {
155✔
3492
      vlog_set_ident(v, p_identifier());
154✔
3493

3494
      if (optional(tEQ))
154✔
3495
         vlog_set_value(v, p_expression());
8✔
3496
   }
3497

3498
   vlog_set_loc(v, CURRENT_LOC);
155✔
3499
   return v;
155✔
3500
}
3501

3502
static void p_tf_port_list(vlog_node_t tf)
129✔
3503
{
3504
   // tf_port_item { , tf_port_item }
3505

3506
   BEGIN("task or function port list");
258✔
3507

3508
   do {
153✔
3509
      vlog_node_t v = p_tf_port_item();
153✔
3510
      vlog_add_port(tf, v);
153✔
3511

3512
      if (vlog_has_ident(v))  // Ignore unnamed ports
153✔
3513
         vlog_symtab_put(symtab, v);
152✔
3514
   } while (optional(tCOMMA));
153✔
3515
}
129✔
3516

3517
static void p_list_of_tf_variable_identifiers(vlog_node_t tf,
99✔
3518
                                              v_port_kind_t kind,
3519
                                              vlog_node_t dt)
3520
{
3521
   // port_identifier { variable_dimension } [ = expression ]
3522
   //    { , port_identifier { variable_dimension } [ = expression ] }
3523

3524
   BEGIN("list of task or function variable identifiers");
198✔
3525

3526
   do {
125✔
3527
      vlog_node_t v = vlog_new(V_TF_PORT_DECL);
125✔
3528
      vlog_set_subkind(v, kind);
125✔
3529
      vlog_set_type(v, dt);
125✔
3530
      vlog_set_ident(v, p_identifier());
125✔
3531
      vlog_set_loc(v, &state.last_loc);
125✔
3532

3533
      if (optional(tEQ))
125✔
3534
         vlog_set_value(v, p_expression());
1✔
3535

3536
      vlog_add_port(tf, v);
125✔
3537
      vlog_symtab_put(symtab, v);
125✔
3538
   } while (optional(tCOMMA));
125✔
3539
}
99✔
3540

3541
static void p_tf_port_declaration(vlog_node_t tf)
99✔
3542
{
3543
   // { attribute_instance } tf_port_direction [ var ] data_type_or_implicit
3544
   //    list_of_tf_variable_identifiers ;
3545

3546
   BEGIN("task or function port declaration");
198✔
3547

3548
   v_port_kind_t kind = p_tf_port_direction();
99✔
3549

3550
   optional(tVAR);
99✔
3551

3552
   vlog_node_t dt = p_data_type_or_implicit();
99✔
3553

3554
   p_list_of_tf_variable_identifiers(tf, kind, dt);
99✔
3555

3556
   consume(tSEMI);
99✔
3557
}
99✔
3558

3559
static void p_tf_item_declaration(vlog_node_t tf)
153✔
3560
{
3561
   // block_item_declaration | tf_port_declaration
3562

3563
   BEGIN("task or function item declaration");
306✔
3564

3565
   switch (peek()) {
153✔
3566
   case tINPUT:
99✔
3567
   case tOUTPUT:
3568
   case tCONST:
3569
      p_tf_port_declaration(tf);
99✔
3570
      break;
99✔
3571
   default:
54✔
3572
      p_block_item_declaration(tf);
54✔
3573
      break;
54✔
3574
   }
3575
}
153✔
3576

3577
static void p_task_body_declaration(vlog_node_t task)
37✔
3578
{
3579
   // [ interface_identifier . | class_scope ] task_identifier ;
3580
   //    { tf_item_declaration } { statement_or_null }
3581
   //    endtask [ : task_identifier ]
3582
   // | [ interface_identifier . | class_scope ] task_identifier
3583
   //    ( [ tf_port_list ] ) ; { block_item_declaration }
3584
   //    { statement_or_null } endtask [ : task_identifier ]
3585

3586
   BEGIN("task body declaration");
74✔
3587

3588
   ident_t id = p_identifier();
37✔
3589
   vlog_set_ident(task, id);
37✔
3590
   vlog_set_loc(task, &state.last_loc);
37✔
3591

3592
   vlog_symtab_put(symtab, task);
37✔
3593

3594
   vlog_symtab_push(symtab, task);
37✔
3595

3596
   if (optional(tLPAREN)) {
37✔
3597
      if (peek() != tRPAREN)
7✔
3598
         p_tf_port_list(task);
7✔
3599
      consume(tRPAREN);
7✔
3600

3601
      consume(tSEMI);
7✔
3602

3603
      skip_over_attributes();
7✔
3604

3605
      while (scan_block_item_declaration()) {
7✔
UNCOV
3606
         p_block_item_declaration(task);
×
UNCOV
3607
         skip_over_attributes();
×
3608
      }
3609
   }
3610
   else {
3611
      consume(tSEMI);
30✔
3612

3613
      skip_over_attributes();
30✔
3614

3615
      while (scan_tf_item_declaration()) {
72✔
3616
         p_tf_item_declaration(task);
42✔
3617
         skip_over_attributes();
42✔
3618
      }
3619
   }
3620

3621
   while (not_at_token(tENDTASK)) {
77✔
3622
      vlog_node_t s = p_statement_or_null();
40✔
3623
      if (s != NULL)
40✔
3624
         vlog_add_stmt(task, s);
40✔
3625
   }
3626

3627
   consume(tENDTASK);
37✔
3628

3629
   if (optional(tCOLON)) {
37✔
3630
      ident_t name = p_identifier();
2✔
3631
      if (id != name)
2✔
3632
         error_at(&state.last_loc, "'%s' does not match task name '%s'",
1✔
3633
                  istr(name), istr(id));
3634
   }
3635

3636
   vlog_symtab_pop(symtab);
37✔
3637
}
37✔
3638

3639
static void p_lifetime(void)
5✔
3640
{
3641
   // static | automatic
3642

3643
   BEGIN("lifetime");
10✔
3644

3645
   one_of(tAUTOMATIC);
5✔
3646
}
5✔
3647

3648
static vlog_node_t p_task_declaration(void)
37✔
3649
{
3650
   // task [ dynamic_override_specifiers ] [ lifetime ] task_body_declaration
3651

3652
   BEGIN("task declaration");
74✔
3653

3654
   vlog_node_t v = vlog_new(V_TASK_DECL);
37✔
3655

3656
   consume(tTASK);
37✔
3657

3658
   if (scan(tAUTOMATIC))
37✔
UNCOV
3659
      p_lifetime();
×
3660

3661
   p_task_body_declaration(v);
37✔
3662

3663
   vlog_set_loc(v, CURRENT_LOC);
37✔
3664
   return v;
37✔
3665
}
3666

3667
static vlog_node_t p_function_data_type_or_implicit(void)
192✔
3668
{
3669
   // data_type_or_void | implicit_data_type
3670

3671
   BEGIN("function data type or implicit");
384✔
3672

3673
   switch (peek()) {
192✔
3674
   case tREG:
47✔
3675
   case tSTRUCT:
3676
   case tUNION:
3677
   case tENUM:
3678
   case tSVINT:
3679
   case tINTEGER:
3680
   case tSVREAL:
3681
   case tSHORTREAL:
3682
   case tREALTIME:
3683
   case tLOGIC:
3684
   case tBIT:
3685
   case tSHORTINT:
3686
   case tSTRINGK:
3687
   case tEVENT:
3688
   case tVOID:
3689
      return p_data_type_or_void();
47✔
3690
   case tID:
23✔
3691
      {
3692
         vlog_node_t dt = peek_reference();
23✔
3693
         if (dt != NULL && is_data_type(dt)) {
23✔
3694
            consume(tID);
1✔
3695
            return dt;
1✔
3696
         }
3697
         else
3698
            return p_implicit_data_type();
22✔
3699
      }
3700
   default:
122✔
3701
      return p_implicit_data_type();
122✔
3702
   }
3703
}
3704

3705
static void p_function_body_declaration(vlog_node_t func)
192✔
3706
{
3707
   // function_data_type_or_implicit [ interface_identifier . | class_scope ]
3708
   //    function_identifier ; { tf_item_declaration }
3709
   //    { function_statement_or_null } endfunction [ : function_identifier ]
3710
   // | function_data_type_or_implicit [ interface_identifier . | class_scope ]
3711
   //    function_identifier ( [ tf_port_list ] ) ; { block_item_declaration }
3712
   //    { function_statement_or_null } endfunction [ : function_identifier ]
3713

3714
   BEGIN("function body declaration");
384✔
3715

3716
   vlog_set_type(func, p_function_data_type_or_implicit());
192✔
3717

3718
   ident_t id = p_identifier();
192✔
3719
   vlog_set_ident(func, id);
192✔
3720
   vlog_set_loc(func, &state.last_loc);
192✔
3721

3722
   vlog_symtab_put(symtab, func);
192✔
3723

3724
   vlog_symtab_push(symtab, func);
192✔
3725

3726
   if (optional(tLPAREN)) {
192✔
3727
      if (peek() != tRPAREN)
125✔
3728
         p_tf_port_list(func);
122✔
3729
      consume(tRPAREN);
125✔
3730

3731
      consume(tSEMI);
125✔
3732

3733
      skip_over_attributes();
125✔
3734

3735
      while (scan_block_item_declaration()) {
165✔
3736
         p_block_item_declaration(func);
40✔
3737
         skip_over_attributes();
40✔
3738
      }
3739
   }
3740
   else {
3741
      consume(tSEMI);
67✔
3742

3743
      skip_over_attributes();
67✔
3744

3745
      while (scan_tf_item_declaration()) {
178✔
3746
         p_tf_item_declaration(func);
111✔
3747
         skip_over_attributes();
111✔
3748
      }
3749
   }
3750

3751
   while (not_at_token(tENDFUNCTION)) {
388✔
3752
      vlog_node_t s = p_statement_or_null();
196✔
3753
      if (s != NULL)
196✔
3754
         vlog_add_stmt(func, s);
196✔
3755
   }
3756

3757
   consume(tENDFUNCTION);
192✔
3758

3759
   if (optional(tCOLON)) {
192✔
3760
      ident_t name = p_identifier();
3✔
3761
      if (id != name)
3✔
3762
         error_at(&state.last_loc, "'%s' does not match function name '%s'",
1✔
3763
                  istr(name), istr(id));
3764
   }
3765

3766
   vlog_symtab_pop(symtab);
192✔
3767
}
192✔
3768

3769
static vlog_node_t p_function_declaration(void)
192✔
3770
{
3771
   // function [ lifetime ] function_body_declaration
3772

3773
   BEGIN("function declaration");
384✔
3774

3775
   vlog_node_t v = vlog_new(V_FUNC_DECL);
192✔
3776

3777
   consume(tFUNCTION);
192✔
3778

3779
   if (scan(tAUTOMATIC))
192✔
3780
      p_lifetime();
5✔
3781

3782
   p_function_body_declaration(v);
192✔
3783

3784
   vlog_set_loc(v, CURRENT_LOC);
192✔
3785
   return v;
192✔
3786
}
3787

3788
static vlog_node_t p_constant_param_expression(void)
562✔
3789
{
3790
   // mintypmax_expression | data_type | $
3791

3792
   BEGIN("constant parameter expression");
1,124✔
3793

3794
   return p_mintypmax_expression();
562✔
3795
}
3796

3797
static vlog_node_t p_param_assignment(vlog_node_t datatype, vlog_kind_t kind)
578✔
3798
{
3799
   // parameter_identifier { unpacked_dimension }
3800
   //   [ = constant_param_expression ]
3801

3802
   BEGIN("parameter assignment");
1,156✔
3803

3804
   vlog_node_t v = vlog_new(kind);
578✔
3805
   vlog_set_ident(v, p_identifier());
578✔
3806
   vlog_set_type(v, datatype);
578✔
3807

3808
   if (optional(tEQ))
578✔
3809
      vlog_set_value(v, p_constant_param_expression());
562✔
3810

3811
   vlog_set_loc(v, CURRENT_LOC);
578✔
3812
   return v;
578✔
3813
}
3814

3815
static void p_list_of_param_assignments(vlog_node_t parent,
516✔
3816
                                        vlog_node_t datatype,
3817
                                        vlog_kind_t kind)
3818
{
3819
   // param_assignment { , param_assignment }
3820

3821
   BEGIN("list of parameter assignments");
1,032✔
3822

3823
   do {
578✔
3824
      vlog_node_t v = p_param_assignment(datatype, kind);
578✔
3825
      vlog_symtab_put(symtab, v);
578✔
3826
      vlog_add_decl(parent, v);
578✔
3827
   } while (peek_nth(2) == tID && optional(tCOMMA));
578✔
3828
}
516✔
3829

3830
static void p_parameter_declaration(vlog_node_t mod)
228✔
3831
{
3832
   // parameter data_type_or_implicit list_of_param_assignments
3833

3834
   BEGIN("parameter declaration");
456✔
3835

3836
   consume(tPARAMETER);
228✔
3837

3838
   vlog_node_t dt = p_data_type_or_implicit();
228✔
3839
   p_list_of_param_assignments(mod, dt, param_kind);
228✔
3840
}
228✔
3841

3842
static void p_local_parameter_declaration(vlog_node_t mod)
286✔
3843
{
3844
   // localparam data_type_or_implicit list_of_param_assignments
3845

3846
   BEGIN("local parameter declaration");
572✔
3847

3848
   consume(tLOCALPARAM);
286✔
3849

3850
   vlog_node_t dt = p_data_type_or_implicit();
286✔
3851
   p_list_of_param_assignments(mod, dt, V_LOCALPARAM);
286✔
3852
}
286✔
3853

3854
static void p_class_property(vlog_node_t parent)
15✔
3855
{
3856
   // { property_qualifier } data_declaration
3857
   //   | const { class_item_qualifier } data_type const_identifier
3858
   //       [ = constant_expression ] ;
3859

3860
   BEGIN("class property");
30✔
3861

3862
   p_data_declaration(parent, V_VAR_DECL);
15✔
3863
}
15✔
3864

3865
static void p_class_constructor_arg(vlog_node_t parent)
2✔
3866
{
3867
   // tf_port_item | default
3868

3869
   BEGIN("class constructor argument");
4✔
3870

3871
   vlog_node_t v = p_tf_port_item();
2✔
3872
   vlog_symtab_put(symtab, v);
2✔
3873
   vlog_add_param(parent, v);
2✔
3874
}
2✔
3875

3876
static void p_class_constructor_arg_list(vlog_node_t parent)
2✔
3877
{
3878
   // class_constructor_arg { , class_constructor_arg }
3879

3880
   BEGIN("class constructor argument list");
4✔
3881

3882
   do {
2✔
3883
      p_class_constructor_arg(parent);
2✔
3884
   } while (optional(tCOMMA));
2✔
3885
}
2✔
3886

3887
static vlog_node_t p_class_constructor_declaration(void)
2✔
3888
{
3889
   // function [ class_scope ] new [ ( [ class_constructor_arg_list ] ) ] ;
3890
   //   { block_item_declaration }
3891
   //   [ super . new [ ( [ list_of_arguments | default ] ) ] ; ]
3892
   //   { function_statement_or_null }
3893
   //   endfunction [ : new]
3894

3895
   BEGIN("class constructor declaration");
4✔
3896

3897
   consume(tFUNCTION);
2✔
3898
   consume(tNEW);
2✔
3899

3900
   vlog_node_t v = vlog_new(V_CONSTRUCTOR);
2✔
3901
   vlog_set_ident(v, ident_new("new"));
2✔
3902

3903
   vlog_symtab_push(symtab, v);
2✔
3904

3905
   if (optional(tLPAREN)) {
2✔
3906
      if (not_at_token(tRPAREN))
2✔
3907
         p_class_constructor_arg_list(v);
2✔
3908

3909
      consume(tRPAREN);
2✔
3910
   }
3911

3912
   consume(tSEMI);
2✔
3913

3914
   skip_over_attributes();
2✔
3915

3916
   while (scan_block_item_declaration()) {
2✔
UNCOV
3917
      p_block_item_declaration(v);
×
UNCOV
3918
      skip_over_attributes();
×
3919
   }
3920

3921
   if (optional(tSUPER)) {
2✔
3922
      consume(tDOT);
1✔
3923
      consume(tNEW);
1✔
3924

3925
      vlog_node_t call = vlog_new(V_SUPER_CALL);
1✔
3926
      vlog_set_loc(call, &state.last_loc);
1✔
3927

3928
      if (optional(tLPAREN)) {
1✔
3929
         p_list_of_arguments(call);
1✔
3930
         consume(tRPAREN);
1✔
3931
      }
3932

3933
      vlog_add_stmt(v, call);
1✔
3934
   }
3935

3936
   while (not_at_token(tENDFUNCTION)) {
5✔
3937
      vlog_node_t s = p_statement_or_null();
3✔
3938
      if (s != NULL)
3✔
3939
         vlog_add_stmt(v, s);
2✔
3940
   }
3941

3942
   consume(tENDFUNCTION);
2✔
3943

3944
   if (optional(tCOLON))
2✔
3945
      consume(tNEW);
2✔
3946

3947
   vlog_symtab_pop(symtab);
2✔
3948

3949
   vlog_set_loc(v, CURRENT_LOC);
2✔
3950
   return v;
2✔
3951
}
3952

3953
static void p_method_qualifier(void)
1✔
3954
{
3955
   // [ pure ] virtual | class_item_qualifier
3956

3957
   BEGIN("method qualifier");
2✔
3958

3959
   consume(tVIRTUAL);
1✔
3960
}
1✔
3961

3962
static void p_class_method(vlog_node_t class)
3✔
3963
{
3964
   // { method_qualifier } task_declaration
3965
   //    | { method_qualifier } function_declaration
3966
   //    | pure virtual { class_item_qualifier } method_prototype ;
3967
   //    | extern { method_qualifier } method_prototype ;
3968
   //    | { method_qualifier } class_constructor_declaration
3969
   //    | extern { method_qualifier } class_constructor_prototype
3970

3971
   BEGIN("class method");
6✔
3972

3973
   if (scan(tVIRTUAL))
3✔
3974
      p_method_qualifier();
1✔
3975

3976
   switch (peek()) {
3✔
3977
   case tFUNCTION:
3✔
3978
      if (peek_nth(2) == tNEW)
3✔
3979
         vlog_add_decl(class, p_class_constructor_declaration());
2✔
3980
      else
3981
         vlog_add_decl(class, p_function_declaration());
1✔
3982
      break;
UNCOV
3983
   default:
×
UNCOV
3984
      one_of(tFUNCTION);
×
UNCOV
3985
      break;
×
3986
   }
3987
}
3✔
3988

3989
static void p_class_item(vlog_node_t parent)
19✔
3990
{
3991
   // { attribute_instance } class_property
3992
   //   | { attribute_instance } class_method
3993
   //   | { attribute_instance } class_constraint
3994
   //   | { attribute_instance } class_declaration
3995
   //   | { attribute_instance } covergroup_declaration
3996
   //   | local_parameter_declaration ;
3997
   //   | parameter_declaration | ;
3998

3999
   BEGIN("class item");
38✔
4000

4001
   optional_attributes();
19✔
4002

4003
   switch (peek()) {
19✔
4004
   case tSEMI:
1✔
4005
      consume(tSEMI);
1✔
4006
      break;
1✔
4007
   case tFUNCTION:
3✔
4008
   case tTASK:
4009
   case tVIRTUAL:
4010
      p_class_method(parent);
3✔
4011
      break;
3✔
4012
   default:
15✔
4013
      p_class_property(parent);
15✔
4014
      break;
15✔
4015
   }
4016
}
19✔
4017

4018
static void p_class_type(void)
2✔
4019
{
4020
   // ps_class_identifier [ parameter_value_assignment ]
4021
   //   { :: class_identifier [ parameter_value_assignment ] }
4022

4023
   BEGIN("class type");
4✔
4024

4025
   (void)p_identifier();
2✔
4026
}
2✔
4027

4028
static vlog_node_t p_class_declaration(void)
12✔
4029
{
4030
   // [ virtual ] class [ lifetime ] class_identifier [ parameter_port_list ]
4031
   //   [ extends class_type [ ( list_of_arguments ) ] ]
4032
   //   [ implements interface_class_type { , interface_class_type } ] ;
4033
   //   { class_item } endclass [ : class_identifier ]
4034

4035
   BEGIN("class declaration");
24✔
4036

4037
   vlog_node_t v = vlog_new(V_CLASS_DECL);
12✔
4038

4039
   optional(tVIRTUAL);
12✔
4040

4041
   consume(tCLASS);
12✔
4042

4043
   ident_t name = p_identifier();
12✔
4044
   vlog_set_ident(v, name);
12✔
4045

4046
   if (optional(tEXTENDS))
12✔
4047
      p_class_type();
2✔
4048

4049
   consume(tSEMI);
12✔
4050

4051
   vlog_symtab_push(symtab, v);
12✔
4052

4053
   while (not_at_token(tENDCLASS))
31✔
4054
      p_class_item(v);
19✔
4055

4056
   vlog_symtab_pop(symtab);
12✔
4057

4058
   consume(tENDCLASS);
12✔
4059

4060
   if (optional(tCOLON)) {
12✔
4061
      ident_t end_name = p_identifier();
10✔
4062
      if (name != end_name)
10✔
4063
         error_at(&state.last_loc, "'%s' does not match class name '%s'",
1✔
4064
                  istr(end_name), istr(name));
4065
   }
4066

4067
   vlog_set_loc(v, CURRENT_LOC);
12✔
4068
   vlog_symtab_put(symtab, v);
12✔
4069
   return v;
12✔
4070
}
4071

4072
static void p_block_item_declaration(vlog_node_t parent)
120✔
4073
{
4074
   // { attribute_instance } data_declaration
4075
   //   | { attribute_instance } local_parameter_declaration ;
4076
   //   | { attribute_instance } parameter_declaration ;
4077
   //   | { attribute_instance } overload_declaration
4078
   //   | { attribute_instance } let_declaration
4079

4080
   BEGIN("block item declaration");
240✔
4081

4082
   optional_attributes();
120✔
4083

4084
   switch (peek()) {
120✔
4085
   case tREG:
120✔
4086
   case tSTRUCT:
4087
   case tUNION:
4088
   case tTYPEDEF:
4089
   case tENUM:
4090
   case tSVINT:
4091
   case tINTEGER:
4092
   case tSVREAL:
4093
   case tSHORTREAL:
4094
   case tREALTIME:
4095
   case tBIT:
4096
   case tLOGIC:
4097
   case tSHORTINT:
4098
   case tTIME:
4099
      p_data_declaration(parent, V_LOCAL_DECL);
120✔
4100
      break;
120✔
UNCOV
4101
   default:
×
4102
      should_not_reach_here();
4103
   }
4104
}
120✔
4105

4106
static void p_package_or_generate_item_declaration(vlog_node_t parent)
5,407✔
4107
{
4108
   // net_declaration | data_declaration | task_declaration
4109
   //   | function_declaration | checker_declaration | dpi_import_export
4110
   //   | extern_constraint_declaration | class_declaration
4111
   //   | class_constructor_declaration | local_parameter_declaration ;
4112
   //   | parameter_declaration ; | covergroup_declaration
4113
   //   | overload_declaration | assertion_item_declaration | ;
4114

4115
   BEGIN("package or generate item declaration");
10,814✔
4116

4117
   switch (peek()) {
5,407✔
4118
   case tWIRE:
946✔
4119
   case tUWIRE:
4120
   case tSUPPLY0:
4121
   case tSUPPLY1:
4122
   case tTRI:
4123
   case tTRI0:
4124
   case tTRI1:
4125
   case tTRIAND:
4126
   case tTRIOR:
4127
   case tTRIREG:
4128
   case tWAND:
4129
   case tWOR:
4130
   case tINTERCONNECT:
4131
      p_net_declaration(parent);
946✔
4132
      break;
946✔
4133
   case tREG:
3,759✔
4134
   case tSTRUCT:
4135
   case tUNION:
4136
   case tTYPEDEF:
4137
   case tENUM:
4138
   case tSVINT:
4139
   case tINTEGER:
4140
   case tSVREAL:
4141
   case tSHORTREAL:
4142
   case tREALTIME:
4143
   case tTIME:
4144
   case tEVENT:
4145
   case tID:
4146
   case tVAR:
4147
   case tLOGIC:
4148
   case tBIT:
4149
   case tSHORTINT:
4150
   case tLONGINT:
4151
   case tBYTE:
4152
   case tSTRINGK:
4153
   case tIMPORT:
4154
      p_data_declaration(parent, V_VAR_DECL);
3,759✔
4155
      break;
3,759✔
4156
   case tTASK:
37✔
4157
      vlog_add_decl(parent, p_task_declaration());
37✔
4158
      break;
37✔
4159
   case tFUNCTION:
191✔
4160
      vlog_add_decl(parent, p_function_declaration());
191✔
4161
      break;
191✔
4162
   case tLOCALPARAM:
281✔
4163
      p_local_parameter_declaration(parent);
281✔
4164
      consume(tSEMI);
281✔
4165
      break;
281✔
4166
   case tPARAMETER:
181✔
4167
      p_parameter_declaration(parent);
181✔
4168
      consume(tSEMI);
181✔
4169
      break;
181✔
4170
   case tCLASS:
12✔
4171
   case tVIRTUAL:
4172
      vlog_add_decl(parent, p_class_declaration());
12✔
4173
      break;
12✔
UNCOV
4174
   default:
×
UNCOV
4175
      one_of(tWIRE, tUWIRE, tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND,
×
4176
             tTRIOR, tTRIREG, tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION,
4177
             tTYPEDEF, tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME,
4178
             tTIME, tEVENT, tID, tVAR, tLOGIC, tBIT, tSHORTINT, tLONGINT, tBYTE,
4179
             tSTRINGK, tIMPORT, tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER,
4180
             tCLASS, tVIRTUAL);
UNCOV
4181
      drop_tokens_until(&state, tSEMI);
×
UNCOV
4182
      break;
×
4183
   }
4184
}
5,407✔
4185

4186
static void p_list_of_genvar_identifiers(vlog_node_t mod, vlog_node_t dt)
14✔
4187
{
4188
   // genvar_identifier { , genvar_identifier }
4189

4190
   BEGIN("list of genvar identifiers");
28✔
4191

4192
   do {
14✔
4193
      vlog_node_t v = vlog_new(V_GENVAR_DECL);
14✔
4194
      vlog_set_ident(v, p_identifier());
14✔
4195
      vlog_set_type(v, dt);
14✔
4196
      vlog_set_loc(v, CURRENT_LOC);
14✔
4197

4198
      vlog_add_decl(mod, v);
14✔
4199

4200
      vlog_symtab_put(symtab, v);
14✔
4201
   } while (optional(tCOMMA));
14✔
4202
}
14✔
4203

4204
static void p_genvar_declaration(vlog_node_t mod)
14✔
4205
{
4206
   // genvar list_of_genvar_identifiers ;
4207

4208
   BEGIN("genvar declaration");
28✔
4209

4210
   consume(tGENVAR);
14✔
4211

4212
   vlog_node_t dt = make_integer_atom_type(DT_INTEGER);
14✔
4213
   vlog_set_flags(dt, VLOG_F_SIGNED);
14✔
4214

4215
   p_list_of_genvar_identifiers(mod, dt);
14✔
4216

4217
   consume(tSEMI);
14✔
4218
}
14✔
4219

4220
static void p_module_or_generate_item_declaration(vlog_node_t mod)
5,397✔
4221
{
4222
   // package_or_generate_item_declaration | genvar_declaration
4223
   //   | clocking_declaration | default clocking clocking_identifier ;
4224
   //   | default disable iff expression_or_dist ;
4225

4226
   BEGIN("module or generate item declaration");
10,794✔
4227

4228
   switch (peek()) {
5,397✔
4229
   case tGENVAR:
14✔
4230
      p_genvar_declaration(mod);
14✔
4231
      break;
14✔
4232
   default:
5,383✔
4233
      p_package_or_generate_item_declaration(mod);
5,383✔
4234
      break;
5,383✔
4235
   }
4236
}
5,397✔
4237

4238
static void p_generate_item(vlog_node_t parent)
134✔
4239
{
4240
   // module_or_generate_item | interface_or_generate_item
4241
   //   | checker_or_generate_item
4242

4243
   BEGIN("generate item");
268✔
4244

4245
   p_module_or_generate_item(parent);
134✔
4246
}
134✔
4247

4248
static vlog_node_t p_generate_block(void)
73✔
4249
{
4250
   // generate_item
4251
   //   | [ generate_block_identifier : ] begin [ : generate_block_identifier ]
4252
   //         { generate_item } end [ : generate_block_identifier ]
4253

4254
   BEGIN("generate block");
146✔
4255

4256
   vlog_node_t b = vlog_new(V_BLOCK);
73✔
4257

4258
   if (scan(tID, tBEGIN)) {
73✔
4259
      if (peek() == tID) {
56✔
4260
         vlog_set_ident(b, p_identifier());
1✔
4261
         consume(tCOLON);
1✔
4262
      }
4263

4264
      consume(tBEGIN);
56✔
4265

4266
      if (optional(tCOLON)) {
56✔
4267
         ident_t name = p_identifier();
28✔
4268
         if (vlog_has_ident(b))    // 1800-2023 section 9.3.5
28✔
4269
            parse_error(&state.last_loc, "cannot specify both a label and a "
1✔
4270
                        "name for the same block");
4271
         else
4272
            vlog_set_ident(b, name);
27✔
4273
      }
4274

4275
      vlog_symtab_push(symtab, b);
56✔
4276

4277
      while (not_at_token(tEND))
154✔
4278
         p_generate_item(b);
98✔
4279

4280
      vlog_symtab_pop(symtab);
56✔
4281

4282
      consume(tEND);
56✔
4283

4284
      if (optional(tCOLON)) {
56✔
4285
         ident_t name = p_identifier();
2✔
4286
         if (!vlog_has_ident(b))
2✔
4287
            parse_error(&state.last_loc, "block does not have a label");
1✔
4288
         else if (name != vlog_ident(b))
1✔
4289
            parse_error(&state.last_loc, "'%s' does not match label '%s'",
1✔
4290
                        istr(name), istr(vlog_ident(b)));
4291
      }
4292
   }
4293
   else
4294
      p_generate_item(b);
17✔
4295

4296
   if (!vlog_has_ident(b))
73✔
4297
      vlog_set_ident(b, default_label("genblk"));
45✔
4298

4299
   vlog_set_loc(b, CURRENT_LOC);
73✔
4300
   return b;
73✔
4301
}
4302

4303
static vlog_node_t p_if_generate_construct(void)
34✔
4304
{
4305
   // if ( constant_expression ) generate_block
4306
   //   { else if ( constant_expression ) generate_block }
4307
   //   [ else generate_block ]
4308

4309
   BEGIN("if generate construct");
68✔
4310

4311
   vlog_node_t v = vlog_new(V_IF_GENERATE);
34✔
4312

4313
   consume(tIF);
34✔
4314
   consume(tLPAREN);
34✔
4315

4316
   vlog_node_t c0 = vlog_new(V_COND);
34✔
4317
   vlog_set_value(c0, p_constant_expression());
34✔
4318

4319
   consume(tRPAREN);
34✔
4320

4321
   vlog_set_loc(c0, CURRENT_LOC);
34✔
4322
   vlog_add_stmt(c0, p_generate_block());
34✔
4323

4324
   vlog_add_cond(v, c0);
34✔
4325

4326
   while (optional(tELSE)) {
44✔
4327
      if (peek() == tIF) {
21✔
4328
         // else if ( constant_expression ) generate_block
4329
         consume(tIF);
10✔
4330
         consume(tLPAREN);
10✔
4331

4332
         vlog_node_t cn = vlog_new(V_COND);
10✔
4333
         vlog_set_value(cn, p_constant_expression());
10✔
4334

4335
         consume(tRPAREN);
10✔
4336

4337
         vlog_set_loc(cn, CURRENT_LOC);
10✔
4338
         vlog_add_stmt(cn, p_generate_block());
10✔
4339

4340
         vlog_add_cond(v, cn);
10✔
4341
      }
4342
      else {
4343
         // else generate_block (no condition = default branch)
4344
         vlog_node_t ce = vlog_new(V_COND);
11✔
4345
         vlog_set_loc(ce, &state.last_loc);
11✔
4346
         vlog_add_stmt(ce, p_generate_block());
11✔
4347

4348
         vlog_add_cond(v, ce);
11✔
4349
         break;
11✔
4350
      }
4351
   }
4352

4353
   vlog_set_loc(v, CURRENT_LOC);
34✔
4354
   return v;
34✔
4355
}
4356

4357
static vlog_node_t p_case_generate_construct(void)
1✔
4358
{
4359
   // case ( constant_expression )
4360
   //   case_generate_item { case_generate_item } endcase
4361
   //
4362
   // Lowered to V_IF_GENERATE with equality comparisons so the existing
4363
   // simplifier and elaborator handle it without a new node kind.
4364

4365
   BEGIN("case generate construct");
2✔
4366

4367
   consume(tCASE);
1✔
4368
   consume(tLPAREN);
1✔
4369

4370
   vlog_node_t selector = p_constant_expression();
1✔
4371

4372
   consume(tRPAREN);
1✔
4373

4374
   vlog_node_t v = vlog_new(V_IF_GENERATE);
1✔
4375

4376
   while (not_at_token(tENDCASE)) {
4✔
4377
      vlog_node_t cn = vlog_new(V_COND);
3✔
4378

4379
      if (optional(tDEFAULT)) {
3✔
4380
         // default branch: no condition (like else)
UNCOV
4381
         optional(tCOLON);
×
4382
      }
4383
      else {
4384
         // case_generate_item: constant_expression { , constant_expression }
4385
         //   : generate_block
4386
         // Build equality comparison: selector == label
4387
         // For multiple labels, OR them: (sel == l1) || (sel == l2)
4388
         vlog_node_t cond = NULL;
4389
         do {
3✔
4390
            vlog_node_t eq = vlog_new(V_BINARY);
3✔
4391
            vlog_set_subkind(eq, V_BINARY_LOG_EQ);
3✔
4392
            vlog_set_left(eq, selector);
3✔
4393
            vlog_set_right(eq, p_constant_expression());
3✔
4394
            vlog_set_loc(eq, CURRENT_LOC);
3✔
4395

4396
            if (cond == NULL) {
3✔
4397
               cond = eq;
4398
            }
4399
            else {
4400
               vlog_node_t lor = vlog_new(V_BINARY);
×
4401
               vlog_set_subkind(lor, V_BINARY_LOG_OR);
×
4402
               vlog_set_left(lor, cond);
×
UNCOV
4403
               vlog_set_right(lor, eq);
×
UNCOV
4404
               vlog_set_loc(lor, CURRENT_LOC);
×
UNCOV
4405
               cond = lor;
×
4406
            }
4407
         } while (optional(tCOMMA));
3✔
4408

4409
         consume(tCOLON);
3✔
4410
         vlog_set_value(cn, cond);
3✔
4411
      }
4412

4413
      vlog_set_loc(cn, CURRENT_LOC);
3✔
4414
      vlog_add_stmt(cn, p_generate_block());
3✔
4415
      vlog_add_cond(v, cn);
3✔
4416
   }
4417

4418
   consume(tENDCASE);
1✔
4419

4420
   vlog_set_loc(v, CURRENT_LOC);
1✔
4421
   return v;
1✔
4422
}
4423

4424
static vlog_node_t p_conditional_generate_construct(void)
35✔
4425
{
4426
   // if_generate_construct | case_generate_construct
4427

4428
   BEGIN("conditional generate construct");
70✔
4429

4430
   switch (peek()) {
35✔
4431
   case tIF:
34✔
4432
      return p_if_generate_construct();
34✔
4433
   case tCASE:
1✔
4434
      return p_case_generate_construct();
1✔
UNCOV
4435
   default:
×
4436
      should_not_reach_here();
4437
   }
4438
}
4439

4440
static vlog_node_t p_genvar_initialization(void)
15✔
4441
{
4442
   // [ genvar ] genvar_identifier = constant_expression
4443

4444
   BEGIN("genvar initialization");
30✔
4445

4446
   vlog_node_t v = vlog_new(V_FOR_INIT);
15✔
4447

4448
   vlog_node_t ref = vlog_new(V_REF);
15✔
4449
   vlog_set_ident(ref, p_identifier());
15✔
4450
   vlog_set_loc(ref, &state.last_loc);
15✔
4451

4452
   vlog_symtab_lookup(symtab, ref);
15✔
4453

4454
   consume(tEQ);
15✔
4455

4456
   vlog_node_t a = vlog_new(V_BASSIGN);
15✔
4457
   vlog_set_target(a, ref);
15✔
4458
   vlog_set_value(a, p_constant_expression());
15✔
4459
   vlog_set_loc(a, CURRENT_LOC);
15✔
4460

4461
   vlog_add_stmt(v, a);
15✔
4462

4463
   vlog_set_loc(v, CURRENT_LOC);
15✔
4464
   return v;
15✔
4465
}
4466

4467
static vlog_node_t p_genvar_iteration(void)
15✔
4468
{
4469
   // genvar_identifier assignment_operator genvar_expression
4470
   //   | inc_or_dec_operator genvar_identifier
4471
   //   | genvar_identifier inc_or_dec_operator
4472

4473
   BEGIN("genvar iteration");
30✔
4474

4475
   vlog_node_t v = vlog_new(V_FOR_STEP);
15✔
4476

4477
   vlog_node_t prefix = NULL;
15✔
4478
   if (scan(tPLUSPLUS, tMINUSMINUS)) {
15✔
4479
      prefix = vlog_new(V_PREFIX);
1✔
4480
      vlog_set_subkind(prefix, p_inc_or_dec_operator());
1✔
4481
   }
4482

4483
   vlog_node_t ref = vlog_new(V_REF);
15✔
4484
   vlog_set_ident(ref, p_identifier());
15✔
4485
   vlog_set_loc(ref, &state.last_loc);
15✔
4486

4487
   vlog_symtab_lookup(symtab, ref);
15✔
4488

4489
   if (prefix != NULL) {
15✔
4490
      vlog_set_target(prefix, ref);
1✔
4491

4492
      vlog_add_stmt(v, prefix);
1✔
4493
   }
4494
   else if (optional(tEQ)) {
14✔
4495
      vlog_node_t a = vlog_new(V_BASSIGN);
13✔
4496
      vlog_set_target(a, ref);
13✔
4497
      vlog_set_value(a, p_constant_expression());
13✔
4498

4499
      vlog_add_stmt(v, a);
13✔
4500
   }
4501
   else {
4502
      vlog_node_t a = vlog_new(V_POSTFIX);
1✔
4503
      vlog_set_subkind(a, p_inc_or_dec_operator());
1✔
4504
      vlog_set_target(a, ref);
1✔
4505

4506
      vlog_add_stmt(v, a);
1✔
4507
   }
4508

4509
   vlog_set_loc(v, CURRENT_LOC);
15✔
4510
   return v;
15✔
4511
}
4512

4513
static vlog_node_t p_loop_generate_construct(void)
15✔
4514
{
4515
   // for ( genvar_initialization ; genvar_expression ; genvar_iteration )
4516
   //   generate_block
4517

4518
   BEGIN("loop generate construct");
30✔
4519

4520
   consume(tFOR);
15✔
4521
   consume(tLPAREN);
15✔
4522

4523
   vlog_node_t v = vlog_new(V_FOR_GENERATE);
15✔
4524

4525
   vlog_symtab_push(symtab, v);
15✔
4526

4527
   vlog_set_left(v, p_genvar_initialization());
15✔
4528

4529
   consume(tSEMI);
15✔
4530

4531
   vlog_set_value(v, p_constant_expression());
15✔
4532

4533
   consume(tSEMI);
15✔
4534

4535
   vlog_set_right(v, p_genvar_iteration());
15✔
4536

4537
   consume(tRPAREN);
15✔
4538

4539
   vlog_add_stmt(v, p_generate_block());
15✔
4540

4541
   vlog_symtab_pop(symtab);
15✔
4542

4543
   vlog_set_loc(v, CURRENT_LOC);
15✔
4544
   return v;
15✔
4545
}
4546

4547
static void p_module_common_item(vlog_node_t mod)
7,300✔
4548
{
4549
   // module_or_generate_item_declaration
4550
   //   | interface_instantiation | program_instantiation
4551
   //   | assertion_item | bind_directive | continuous_assign
4552
   //   | net_alias | initial_construct | final_construct
4553
   //   | always_construct | loop_generate_construct
4554
   //   | conditional_generate_construct | elaboration_system_task
4555

4556
   BEGIN("module common item");
14,600✔
4557

4558
   switch (peek()) {
7,300✔
4559
   case tALWAYS:
326✔
4560
   case tALWAYSCOMB:
4561
   case tALWAYSFF:
4562
   case tALWAYSLATCH:
4563
      vlog_add_stmt(mod, p_always_construct());
326✔
4564
      break;
326✔
4565
   case tINITIAL:
857✔
4566
      vlog_add_stmt(mod, p_initial_construct());
857✔
4567
      break;
857✔
4568
   case tWIRE:
5,370✔
4569
   case tUWIRE:
4570
   case tSUPPLY0:
4571
   case tSUPPLY1:
4572
   case tTRI:
4573
   case tTRI0:
4574
   case tTRI1:
4575
   case tTRIAND:
4576
   case tTRIOR:
4577
   case tTRIREG:
4578
   case tWAND:
4579
   case tWOR:
4580
   case tINTERCONNECT:
4581
   case tREG:
4582
   case tSTRUCT:
4583
   case tUNION:
4584
   case tTYPEDEF:
4585
   case tENUM:
4586
   case tSVINT:
4587
   case tINTEGER:
4588
   case tSVREAL:
4589
   case tSHORTREAL:
4590
   case tREALTIME:
4591
   case tTIME:
4592
   case tTASK:
4593
   case tFUNCTION:
4594
   case tLOCALPARAM:
4595
   case tPARAMETER:
4596
   case tEVENT:
4597
   case tID:
4598
   case tGENVAR:
4599
   case tVAR:
4600
   case tLOGIC:
4601
   case tBIT:
4602
   case tSHORTINT:
4603
   case tLONGINT:
4604
   case tBYTE:
4605
   case tSTRINGK:
4606
   case tIMPORT:
4607
      p_module_or_generate_item_declaration(mod);
5,370✔
4608
      break;
5,370✔
4609
   case tASSIGN:
696✔
4610
      p_continuous_assign(mod);
696✔
4611
      break;
696✔
4612
   case tFOR:
15✔
4613
      vlog_add_stmt(mod, p_loop_generate_construct());
15✔
4614
      break;
15✔
4615
   case tIF:
35✔
4616
   case tCASE:
4617
      vlog_add_stmt(mod, p_conditional_generate_construct());
35✔
4618
      break;
35✔
4619
   case tFINAL:
1✔
4620
      vlog_add_stmt(mod, p_final_construct());
1✔
4621
      break;
1✔
UNCOV
4622
   default:
×
UNCOV
4623
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
×
4624
             tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
4625
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM,
4626
             tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTIME, tTASK,
4627
             tFUNCTION, tPARAMETER, tLOCALPARAM, tEVENT, tID, tGENVAR, tVAR,
4628
             tLOGIC, tBIT, tSHORTINT, tLONGINT, tBYTE, tSTRINGK, tIMPORT,
4629
             tASSIGN, tFOR, tIF, tCASE, tFINAL);
UNCOV
4630
      drop_tokens_until(&state, tSEMI);
×
4631
   }
4632
}
7,300✔
4633

4634
static vlog_strength_t p_strength0(void)
62✔
4635
{
4636
   // supply0 | strong0 | pull0 | weak0
4637

4638
   BEGIN("strength0");
124✔
4639

4640
   switch (one_of(tSUPPLY0, tSTRONG0, tPULL0, tWEAK0)) {
62✔
4641
   default:
4642
   case tSUPPLY0: return V_STRENGTH_SUPPLY;
4643
   case tSTRONG0: return V_STRENGTH_STRONG;
4644
   case tPULL0:   return V_STRENGTH_PULL;
4645
   case tWEAK0:   return V_STRENGTH_WEAK;
4646
   }
4647
}
4648

4649
static vlog_strength_t p_strength1(void)
64✔
4650
{
4651
   // supply1 | strong1 | pull1 | weak1
4652

4653
   BEGIN("strength1");
128✔
4654

4655
   switch (one_of(tSUPPLY1, tSTRONG1, tPULL1, tWEAK1)) {
64✔
4656
   default:
4657
   case tSUPPLY1: return V_STRENGTH_SUPPLY;
4658
   case tSTRONG1: return V_STRENGTH_STRONG;
4659
   case tPULL1:   return V_STRENGTH_PULL;
4660
   case tWEAK1:   return V_STRENGTH_WEAK;
4661
   }
4662
}
4663

4664
static vlog_node_t p_pulldown_strength(void)
2✔
4665
{
4666
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength0 )
4667

4668
   BEGIN("pulldown strength");
4✔
4669

4670
   consume(tLPAREN);
2✔
4671

4672
   vlog_strength_t s0, s1;
2✔
4673
   switch (peek()) {
2✔
UNCOV
4674
   case tSUPPLY1:
×
4675
   case tSTRONG1:
4676
   case tPULL1:
4677
   case tWEAK1:
4678
      s1 = p_strength1();
×
UNCOV
4679
      consume(tCOMMA);
×
UNCOV
4680
      s0 = p_strength0();
×
UNCOV
4681
      break;
×
4682
   default:
2✔
4683
      s0 = s1 = p_strength0();
2✔
4684
      if (optional(tCOMMA))
2✔
UNCOV
4685
         s1 = p_strength1();
×
4686
      break;
4687
   }
4688

4689
   consume(tRPAREN);
2✔
4690

4691
   vlog_node_t v = vlog_new(V_STRENGTH);
2✔
4692
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
2✔
4693
   vlog_set_loc(v, CURRENT_LOC);
2✔
4694
   return v;
2✔
4695
}
4696

4697
static vlog_node_t p_pullup_strength(void)
7✔
4698
{
4699
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength1 )
4700

4701
   BEGIN("pullup strength");
14✔
4702

4703
   consume(tLPAREN);
7✔
4704

4705
   vlog_strength_t s0, s1;
7✔
4706
   switch (peek()) {
7✔
4707
   case tSUPPLY0:
1✔
4708
   case tSTRONG0:
4709
   case tPULL0:
4710
   case tWEAK0:
4711
      s0 = p_strength0();
1✔
4712
      consume(tCOMMA);
1✔
4713
      s1 = p_strength1();
1✔
4714
      break;
1✔
4715
   default:
6✔
4716
      s1 = s0 = p_strength1();
6✔
4717
      if (optional(tCOMMA))
6✔
4718
         s0 = p_strength0();
1✔
4719
      break;
4720
   }
4721

4722
   consume(tRPAREN);
7✔
4723

4724
   vlog_node_t v = vlog_new(V_STRENGTH);
7✔
4725
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
7✔
4726
   vlog_set_loc(v, CURRENT_LOC);
7✔
4727
   return v;
7✔
4728
}
4729

4730
static vlog_node_t p_pull_gate_instance(vlog_gate_kind_t kind, vlog_node_t st)
22✔
4731
{
4732
   // [ name_of_instance ] ( output_terminal )
4733

4734
   BEGIN("pull gate instance");
44✔
4735

4736
   vlog_node_t v = vlog_new(V_GATE_INST);
22✔
4737
   vlog_set_subkind(v, kind);
22✔
4738
   vlog_add_param(v, st);
22✔
4739

4740
   if (peek() == tID) {
22✔
4741
      vlog_set_ident(v, p_identifier());
7✔
4742
      vlog_set_loc(v, &state.last_loc);
7✔
4743
      vlog_symtab_put(symtab, v);
7✔
4744
   }
4745
   else
4746
      vlog_set_ident(v, default_label("gate"));
15✔
4747

4748
   consume(tLPAREN);
22✔
4749

4750
   vlog_symtab_set_implicit(symtab, implicit_kind);
22✔
4751

4752
   vlog_set_target(v, p_net_lvalue());
22✔
4753

4754
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
22✔
4755

4756
   consume(tRPAREN);
22✔
4757

4758
   vlog_set_loc(v, CURRENT_LOC);
22✔
4759
   return v;
22✔
4760
}
4761

4762
static vlog_node_t p_n_terminal_gate_instance(vlog_gate_kind_t kind,
59✔
4763
                                              vlog_node_t st)
4764
{
4765
   // [ name_of_instance ] ( output_terminal , input_terminal
4766
   //     { , input_terminal } )
4767

4768
   BEGIN("N-terminal gate instance");
118✔
4769

4770
   vlog_node_t v = vlog_new(V_GATE_INST);
59✔
4771
   vlog_set_subkind(v, kind);
59✔
4772

4773
   if (peek() == tID) {
59✔
4774
      vlog_set_ident(v, p_identifier());
21✔
4775
      vlog_set_loc(v, &state.last_loc);
21✔
4776
      vlog_symtab_put(symtab, v);
21✔
4777
   }
4778
   else
4779
      vlog_set_ident(v, default_label("gate"));
38✔
4780

4781
   consume(tLPAREN);
59✔
4782

4783
   vlog_symtab_set_implicit(symtab, implicit_kind);
59✔
4784

4785
   vlog_set_target(v, p_net_lvalue());
59✔
4786

4787
   consume(tCOMMA);
59✔
4788

4789
   do {
80✔
4790
      vlog_add_param(v, p_expression());
80✔
4791
   } while (optional(tCOMMA));
80✔
4792

4793
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
59✔
4794

4795
   consume(tRPAREN);
59✔
4796

4797
   vlog_set_loc(v, CURRENT_LOC);
59✔
4798
   return v;
59✔
4799
}
4800

4801
static vlog_node_t p_enable_gate_instance(vlog_gate_kind_t kind,
5✔
4802
                                          vlog_node_t st)
4803
{
4804
   // [ name_of_instance ] ( output_terminal , input_terminal ,
4805
   //     enable_terminal )
4806

4807
   BEGIN("enable gate instance");
10✔
4808

4809
   vlog_node_t v = vlog_new(V_GATE_INST);
5✔
4810
   vlog_set_subkind(v, kind);
5✔
4811
   vlog_add_param(v, st);
5✔
4812

4813
   if (peek() == tID) {
5✔
4814
      vlog_set_ident(v, p_identifier());
4✔
4815
      vlog_set_loc(v, &state.last_loc);
4✔
4816
      vlog_symtab_put(symtab, v);
4✔
4817
   }
4818
   else
4819
      vlog_set_ident(v, default_label("gate"));
1✔
4820

4821
   consume(tLPAREN);
5✔
4822

4823
   vlog_symtab_set_implicit(symtab, implicit_kind);
5✔
4824

4825
   vlog_set_target(v, p_net_lvalue());
5✔
4826

4827
   consume(tCOMMA);
5✔
4828

4829
   vlog_add_param(v, p_expression());
5✔
4830

4831
   consume(tCOMMA);
5✔
4832

4833
   vlog_add_param(v, p_expression());
5✔
4834

4835
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
5✔
4836

4837
   consume(tRPAREN);
5✔
4838

4839
   vlog_set_loc(v, CURRENT_LOC);
5✔
4840
   return v;
5✔
4841
}
4842

4843
static vlog_node_t p_pass_switch_instance(vlog_gate_kind_t kind)
1✔
4844
{
4845
   // [ name_of_instance ] ( inout_terminal , inout_terminal )
4846

4847
   BEGIN("pass switch instance");
2✔
4848

4849
   vlog_node_t v = vlog_new(V_GATE_INST);
1✔
4850
   vlog_set_subkind(v, kind);
1✔
4851

4852
   if (peek() == tID) {
1✔
UNCOV
4853
      vlog_set_ident(v, p_identifier());
×
UNCOV
4854
      vlog_set_loc(v, &state.last_loc);
×
UNCOV
4855
      vlog_symtab_put(symtab, v);
×
4856
   }
4857
   else
4858
      vlog_set_ident(v, default_label("gate"));
1✔
4859

4860
   consume(tLPAREN);
1✔
4861

4862
   vlog_symtab_set_implicit(symtab, implicit_kind);
1✔
4863

4864
   vlog_set_target(v, p_net_lvalue());
1✔
4865

4866
   consume(tCOMMA);
1✔
4867

4868
   vlog_add_param(v, p_net_lvalue());
1✔
4869

4870
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
1✔
4871

4872
   consume(tRPAREN);
1✔
4873

4874
   vlog_set_loc(v, CURRENT_LOC);
1✔
4875
   return v;
1✔
4876
}
4877

4878
static vlog_node_t p_pass_enable_switch_instance(vlog_gate_kind_t kind)
1✔
4879
{
4880
   // [ name_of_instance ] ( inout_terminal , inout_terminal ,
4881
   //     enable_terminal )
4882

4883
   BEGIN("pass enable switch instance");
2✔
4884

4885
   vlog_node_t v = vlog_new(V_GATE_INST);
1✔
4886
   vlog_set_subkind(v, kind);
1✔
4887

4888
   if (peek() == tID) {
1✔
UNCOV
4889
      vlog_set_ident(v, p_identifier());
×
UNCOV
4890
      vlog_set_loc(v, &state.last_loc);
×
UNCOV
4891
      vlog_symtab_put(symtab, v);
×
4892
   }
4893
   else
4894
      vlog_set_ident(v, default_label("gate"));
1✔
4895

4896
   consume(tLPAREN);
1✔
4897

4898
   vlog_symtab_set_implicit(symtab, implicit_kind);
1✔
4899

4900
   vlog_set_target(v, p_net_lvalue());
1✔
4901

4902
   consume(tCOMMA);
1✔
4903

4904
   vlog_add_param(v, p_net_lvalue());
1✔
4905

4906
   consume(tCOMMA);
1✔
4907

4908
   vlog_add_param(v, p_expression());
1✔
4909

4910
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
1✔
4911

4912
   consume(tRPAREN);
1✔
4913

4914
   vlog_set_loc(v, CURRENT_LOC);
1✔
4915
   return v;
1✔
4916
}
4917

4918
static void p_gate_instantiation(vlog_node_t mod)
88✔
4919
{
4920
   // cmos_switchtype [ delay3 ] cmos_switch_instance
4921
   //     { , cmos_switch_instance } ;
4922
   //  | enable_gatetype [ drive_strength ] [ delay3 ]
4923
   //     enable_gate_instance { , enable_gate_instance } ;
4924
   //  | mos_switchtype [ delay3 ] mos_switch_instance
4925
   //     { , mos_switch_instance } ;
4926
   //  | n_input_gatetype [ drive_strength ] [ delay2 ] n_input_gate_instance
4927
   //     { , n_input_gate_instance } ;
4928
   //  | n_output_gatetype [ drive_strength ] [ delay2 ] n_output_gate_instance
4929
   //     { , n_output_gate_instance } ;
4930
   //  | pass_en_switchtype [ delay2 ] pass_enable_switch_instance
4931
   //     { , pass_enable_switch_instance } ;
4932
   //  | pass_switchtype pass_switch_instance { , pass_switch_instance } ;
4933
   //  | pulldown [ pulldown_strength ] pull_gate_instance
4934
   //     { , pull_gate_instance } ;
4935
   //  | pullup [ pullup_strength ] pull_gate_instance
4936
   //     { , pull_gate_instance } ;
4937

4938
   BEGIN("gate instantiation");
176✔
4939

4940
   token_t token = one_of(tPULLDOWN, tPULLUP, tAND, tNAND, tOR, tNOR,
88✔
4941
                          tXOR, tXNOR, tNOT, tBUF, tBUFIF0, tBUFIF1,
4942
                          tNOTIF0, tNOTIF1, tTRAN, tRTRAN, tTRANIF0, tTRANIF1,
4943
                          tRTRANIF0, tRTRANIF1);
4944

4945
   switch (token) {
88✔
4946
   case tPULLDOWN:
8✔
4947
      {
4948
         vlog_node_t st;
8✔
4949
         if (peek() == tLPAREN && peek_nth(2) != tID)
8✔
4950
            st = p_pulldown_strength();
2✔
4951
         else {
4952
            st = vlog_new(V_STRENGTH);
6✔
4953
            vlog_set_subkind(st, ST_PULLUP);
6✔
4954
         }
4955

4956
         do {
8✔
4957
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLDOWN, st);
8✔
4958
            vlog_add_stmt(mod, g);
8✔
4959
         } while (optional(tCOMMA));
8✔
4960
      }
4961
      break;
4962

4963
   case tPULLUP:
14✔
4964
      {
4965
         vlog_node_t st;
14✔
4966
         if (peek() == tLPAREN && peek_nth(2) != tID)
14✔
4967
            st = p_pullup_strength();
7✔
4968
         else {
4969
            st = vlog_new(V_STRENGTH);
7✔
4970
            vlog_set_subkind(st, ST_PULLUP);
7✔
4971
         }
4972

4973
         do {
14✔
4974
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLUP, st);
14✔
4975
            vlog_add_stmt(mod, g);
14✔
4976
         } while (optional(tCOMMA));
14✔
4977
      }
4978
      break;
4979

4980
   case tAND:
59✔
4981
   case tNAND:
4982
   case tOR:
4983
   case tNOR:
4984
   case tXOR:
4985
   case tXNOR:
4986
   case tNOT:
4987
   case tBUF:
4988
      {
4989
         vlog_node_t st;
59✔
4990
         if (peek() == tLPAREN && peek_nth(2) != tID)
59✔
4991
            st = p_drive_strength();
1✔
4992
         else {
4993
            st = vlog_new(V_STRENGTH);
58✔
4994
            vlog_set_subkind(st, ST_STRONG);
58✔
4995
         }
4996

4997
         const vlog_gate_kind_t kind = get_gate_kind(token);
59✔
4998

4999
         if (peek() == tHASH)
59✔
5000
            p_delay2();
2✔
5001

5002
         do {
59✔
5003
            vlog_add_stmt(mod, p_n_terminal_gate_instance(kind, st));
59✔
5004
         } while (optional(tCOMMA));
59✔
5005
      }
5006
      break;
5007

5008
   case tBUFIF0:
5✔
5009
   case tBUFIF1:
5010
   case tNOTIF0:
5011
   case tNOTIF1:
5012
      {
5013
         vlog_node_t st;
5✔
5014
         if (peek() == tLPAREN && peek_nth(2) != tID)
5✔
5015
            st = p_drive_strength();
1✔
5016
         else {
5017
            st = vlog_new(V_STRENGTH);
4✔
5018
            vlog_set_subkind(st, ST_STRONG);
4✔
5019
         }
5020

5021
         if (peek() == tHASH)
5✔
UNCOV
5022
            p_delay3();
×
5023

5024
         const vlog_gate_kind_t kind = get_gate_kind(token);
5✔
5025

5026
         do {
5✔
5027
            vlog_add_stmt(mod, p_enable_gate_instance(kind, st));
5✔
5028
         } while (optional(tCOMMA));
5✔
5029
      }
5030
      break;
5031

5032
   case tTRAN:
1✔
5033
   case tRTRAN:
5034
      {
5035
         const vlog_gate_kind_t kind = get_gate_kind(token);
1✔
5036

5037
         do {
1✔
5038
            vlog_add_stmt(mod, p_pass_switch_instance(kind));
1✔
5039
         } while (optional(tCOMMA));
1✔
5040
      }
5041
      break;
5042

5043
   case tTRANIF0:
1✔
5044
   case tTRANIF1:
5045
   case tRTRANIF0:
5046
   case tRTRANIF1:
5047
      {
5048
         if (peek() == tHASH)
1✔
UNCOV
5049
            p_delay2();
×
5050

5051
         const vlog_gate_kind_t kind = get_gate_kind(token);
1✔
5052

5053
         do {
1✔
5054
            vlog_add_stmt(mod, p_pass_enable_switch_instance(kind));
1✔
5055
         } while (optional(tCOMMA));
1✔
5056
      }
5057
      break;
5058

5059
   default:
5060
      break;
5061
   }
5062

5063
   consume(tSEMI);
88✔
5064
}
88✔
5065

5066
static vlog_node_t p_module_path_expression(void)
4✔
5067
{
5068
   // module_path_primary
5069
   //   | unary_module_path_operator { attribute_instance } module_path_primary
5070
   //   | module_path_expression binary_module_path_operator
5071
   //      { attribute_instance } module_path_expression
5072
   //   | module_path_conditional_expression
5073

5074
   BEGIN("module path expression");
8✔
5075

5076
   // TODO: sem should check valid subset
5077
   return p_expression();
4✔
5078
}
5079

5080
static void p_path_delay_expression(void)
22✔
5081
{
5082
   // constant_expression
5083
   //   | constant_expression : constant_expression : constant_expression
5084

5085
   BEGIN("path delay expression");
44✔
5086

5087
   (void)p_constant_expression();
22✔
5088
}
22✔
5089

5090
static void p_list_of_path_delay_expressions(void)
18✔
5091
{
5092
   // path_delay_expression { , path_delay_expression }
5093

5094
   BEGIN("list of path delay expressions");
36✔
5095

5096
   do {
22✔
5097
      p_path_delay_expression();
22✔
5098
   } while (optional(tCOMMA));
22✔
5099
}
18✔
5100

5101
static void p_path_delay_value(void)
18✔
5102
{
5103
   // list_of_path_delay_expressions | ( list_of_path_delay_expressions )
5104

5105
   BEGIN("path delay value");
36✔
5106

5107
   if (optional(tLPAREN)) {
18✔
5108
      p_list_of_path_delay_expressions();
4✔
5109
      consume(tRPAREN);
4✔
5110
   }
5111
   else
5112
      p_list_of_path_delay_expressions();
14✔
5113
}
18✔
5114

5115
static vlog_node_t p_specify_terminal_descriptor(void)
76✔
5116
{
5117
   // identifier [ [ constant_range_expression ] ]
5118

5119
   BEGIN("specify terminal descriptor");
152✔
5120

5121
   vlog_node_t v = vlog_new(V_REF);
76✔
5122
   vlog_set_ident(v, p_identifier());
76✔
5123
   vlog_set_loc(v, CURRENT_LOC);
76✔
5124

5125
   if (optional(tLSQUARE)) {
76✔
5126
      (void)p_constant_range_expression();
2✔
5127
      consume(tRSQUARE);
2✔
5128
   }
5129

5130
   return v;
76✔
5131
}
5132

5133
static void p_list_of_path_inputs(vlog_node_t v, vlog_node_t head)
8✔
5134
{
5135
   // specify_input_terminal_descriptor { , specify_input_terminal_descriptor }
5136

5137
   BEGIN_WITH_HEAD("list of path inputs", head);
16✔
5138

5139
   while (optional(tCOMMA))
15✔
5140
      (void)p_specify_terminal_descriptor();
7✔
5141
}
8✔
5142

5143
static void p_list_of_path_outputs(vlog_node_t v)
8✔
5144
{
5145
   // specify_output_terminal_descriptor
5146
   //     { , specify_output_terminal_descriptor }
5147

5148
   BEGIN("list of path outputs");
16✔
5149

5150
   do {
17✔
5151
      (void)p_specify_terminal_descriptor();
17✔
5152
   } while (optional(tCOMMA));
17✔
5153
}
8✔
5154

5155
static void p_polarity_operator(void)
9✔
5156
{
5157
   // + | -
5158

5159
   BEGIN("polarity operator");
18✔
5160

5161
   (void)one_of(tPLUS, tMINUS);
9✔
5162
}
9✔
5163

5164
static vlog_node_t p_parallel_path_description(vlog_node_t head)
8✔
5165
{
5166
   // ( specify_input_terminal_descriptor [ polarity_operator ]
5167
   //     => specify_output_terminal_descriptor )
5168

5169
   EXTEND("parallel path description");
16✔
5170

5171
   if (scan(tPLUS, tMINUS))
8✔
5172
      (void)p_polarity_operator();
3✔
5173

5174
   consume(tASSOC);
8✔
5175

5176
   (void)p_specify_terminal_descriptor();
8✔
5177

5178
   consume(tRPAREN);
8✔
5179
   return NULL;
8✔
5180
}
5181

5182
static vlog_node_t p_full_path_description(vlog_node_t head)
3✔
5183
{
5184
   // ( list_of_path_inputs [ polarity_operator ] *> list_of_path_outputs )
5185

5186
   EXTEND("full path description");
6✔
5187

5188
   p_list_of_path_inputs(NULL, head);
3✔
5189

5190
   if (scan(tPLUS, tMINUS))
3✔
5191
      (void)p_polarity_operator();
3✔
5192

5193
   consume(tTIMESGT);
3✔
5194

5195
   p_list_of_path_outputs(NULL);
3✔
5196

5197
   consume(tRPAREN);
3✔
5198
   return NULL;
3✔
5199
}
5200

5201
static vlog_node_t p_simple_path_declaration(void)
11✔
5202
{
5203
   // parallel_path_description = path_delay_value
5204
   //   | full_path_description = path_delay_value
5205

5206
   BEGIN("simple path declaration");
22✔
5207

5208
   // Parse up to the first terminal descriptor to determine which
5209
   // production to use
5210

5211
   consume(tLPAREN);
11✔
5212

5213
   vlog_node_t head = p_specify_terminal_descriptor();
11✔
5214

5215
   if (scan(tCOMMA, tTIMESGT) || peek_nth(2) == tTIMESGT)
11✔
5216
      (void)p_full_path_description(head);
3✔
5217
   else
5218
      (void)p_parallel_path_description(head);
8✔
5219

5220
   consume(tEQ);
11✔
5221

5222
   (void)p_path_delay_value();
11✔
5223

5224
   return NULL;
11✔
5225
}
5226

5227
static void p_edge_identifier(void)
7✔
5228
{
5229
   // posedge | negedge | edge
5230

5231
   BEGIN("edge identifier");
14✔
5232

5233
   one_of(tPOSEDGE, tNEGEDGE, tEDGE);
7✔
5234
}
7✔
5235

5236
static vlog_node_t p_parallel_edge_sensitive_path_description(vlog_node_t head)
2✔
5237
{
5238
   // ( [ edge_identifier ] specify_input_terminal_descriptor
5239
   //     [ polarity_operator ] => ( specify_output_terminal_descriptor
5240
   //     [ polarity_operator ] : data_source_expression ) )
5241

5242
   EXTEND("parallel edge sensitive path description");
4✔
5243

5244
   if (scan(tPLUS, tMINUS))
2✔
UNCOV
5245
      (void)p_polarity_operator();
×
5246

5247
   consume(tASSOC);
2✔
5248

5249
   consume(tLPAREN);
2✔
5250

5251
   (void)p_specify_terminal_descriptor();
2✔
5252

5253
   if (scan(tPLUS, tMINUS)) {
2✔
UNCOV
5254
      (void)p_polarity_operator();
×
UNCOV
5255
      consume(tCOLON);
×
5256
   }
5257
   else if (scan(tINDEXPOS, tINDEXNEG))
2✔
5258
      consume(peek());  // Lexing ambiguity with +: and -:
1✔
5259
   else
5260
      consume(tCOLON);
1✔
5261

5262
   (void)p_expression();
2✔
5263

5264
   consume(tRPAREN);
2✔
5265
   consume(tRPAREN);
2✔
5266
   return NULL;
2✔
5267
}
5268

5269
static vlog_node_t p_full_edge_sensitive_path_description(vlog_node_t head)
5✔
5270
{
5271
   // ( [ edge_identifier ] list_of_path_inputs [ polarity_operator ] *>
5272
   //     ( list_of_path_outputs [ polarity_operator ]
5273
   //     : data_source_expression ) )
5274

5275
   EXTEND("full edge sensitive path description");
10✔
5276

5277
   p_list_of_path_inputs(NULL, head);
5✔
5278

5279
   if (scan(tPLUS, tMINUS))
5✔
5280
      (void)p_polarity_operator();
3✔
5281

5282
   consume(tTIMESGT);
5✔
5283

5284
   consume(tLPAREN);
5✔
5285

5286
   p_list_of_path_outputs(NULL);
5✔
5287

5288
   if (scan(tPLUS, tMINUS)) {
5✔
UNCOV
5289
      (void)p_polarity_operator();
×
UNCOV
5290
      consume(tCOLON);
×
5291
   }
5292
   else if (scan(tINDEXPOS, tINDEXNEG))
5✔
5293
      consume(peek());  // Lexing ambiguity with +: and -:
2✔
5294
   else
5295
      consume(tCOLON);
3✔
5296

5297
   (void)p_expression();
5✔
5298

5299
   consume(tRPAREN);
5✔
5300
   consume(tRPAREN);
5✔
5301
   return NULL;
5✔
5302
}
5303

5304
static vlog_node_t p_edge_sensitive_path_declaration(void)
7✔
5305
{
5306
   // parallel_edge_sensitive_path_description = path_delay_value
5307
   //   | full_edge_sensitive_path_description = path_delay_value
5308

5309
   BEGIN("edge sensitive path declaration");
14✔
5310

5311
   // Parse up to the first terminal descriptor to determine which
5312
   // production to use
5313

5314
   consume(tLPAREN);
7✔
5315

5316
   if (scan(tEDGE, tPOSEDGE, tNEGEDGE))
7✔
5317
      p_edge_identifier();
7✔
5318

5319
   vlog_node_t head = p_specify_terminal_descriptor();
7✔
5320

5321
   if (scan(tCOMMA, tTIMESGT) || peek_nth(2) == tTIMESGT)
7✔
5322
      (void)p_full_edge_sensitive_path_description(head);
5✔
5323
   else
5324
      (void)p_parallel_edge_sensitive_path_description(head);
2✔
5325

5326
   consume(tEQ);
7✔
5327

5328
   (void)p_path_delay_value();
7✔
5329

5330
   return NULL;
7✔
5331
}
5332

5333
static vlog_node_t p_state_dependent_path_declaration(void)
6✔
5334
{
5335
   // if ( module_path_expression ) simple_path_declaration
5336
   //   | if ( module_path_expression ) edge_sensitive_path_declaration
5337
   //   | ifnone simple_path_declaration
5338

5339
   BEGIN("state dependent path declaration");
12✔
5340

5341
   switch (one_of(tIF, tIFNONE)) {
6✔
5342
   case tIF:
4✔
5343
      consume(tLPAREN);
4✔
5344
      (void)p_module_path_expression();
4✔
5345
      consume(tRPAREN);
4✔
5346
      break;
4✔
5347
   case tIFNONE:
5348
      break;
5349
   }
5350

5351
   if (peek_nth(2) == tID)
6✔
5352
      (void)p_simple_path_declaration();
2✔
5353
   else {
5354
      // This is invalid for ifnone according to the grammar but is
5355
      // accepted by some simulators and seen in the wild
5356
      (void)p_edge_sensitive_path_declaration();
4✔
5357
   }
5358

5359
   return NULL;
6✔
5360
}
5361

5362
static vlog_node_t p_path_declaration(void)
18✔
5363
{
5364
   // simple_path_declaration ;
5365
   //  | edge_sensitive_path_declaration ;
5366
   //  | state_dependent_path_declaration ;
5367

5368
   BEGIN("path declaration");
36✔
5369

5370
   switch (peek()) {
18✔
5371
   case tIF:
6✔
5372
   case tIFNONE:
5373
      (void)p_state_dependent_path_declaration();
6✔
5374
      break;
6✔
5375
   case tLPAREN:
12✔
5376
      switch (peek_nth(2)) {
12✔
5377
      case tEDGE:
3✔
5378
      case tNEGEDGE:
5379
      case tPOSEDGE:
5380
         (void)p_edge_sensitive_path_declaration();
3✔
5381
         break;
3✔
5382
      default:
9✔
5383
         (void)p_simple_path_declaration();
9✔
5384
         break;
9✔
5385
      }
5386
      break;
UNCOV
5387
   default:
×
UNCOV
5388
      one_of(tIF, tIFNONE);
×
5389
   }
5390

5391
   consume(tSEMI);
18✔
5392
   return NULL;
18✔
5393
}
5394

5395
static void p_timing_check_event_control(void)
8✔
5396
{
5397
   // posedge | negedge | edge | edge_control_specifier
5398

5399
   BEGIN("timing check event control");
16✔
5400

5401
   one_of(tPOSEDGE, tNEGEDGE, tEDGE);
8✔
5402
}
8✔
5403

5404
static void p_scalar_timing_check_condition(void)
4✔
5405
{
5406
   //    expression
5407
   // | ~ expression
5408
   // | expression == scalar_constant
5409
   // | expression === scalar_constant
5410
   // | expression != scalar_constant
5411
   // | expression !== scalar_constant
5412

5413
   BEGIN("scalar timing check condition")
8✔
5414

5415
   p_expression();
4✔
5416
}
4✔
5417

5418
static void p_timing_check_condition(void)
4✔
5419
{
5420
   //     scalar_timing_check_condition
5421
   // | ( scalar_timing_check_condition )
5422

5423
   BEGIN("timing check condition");
8✔
5424

5425
   if (optional(tLPAREN)) {
4✔
5426
      p_scalar_timing_check_condition();
1✔
5427
      consume(tRPAREN);
1✔
5428
   }
5429
   else
5430
      p_scalar_timing_check_condition();
3✔
5431
}
4✔
5432

5433
static vlog_node_t p_timing_check_event(void)
20✔
5434
{
5435
   // [ timing_check_event_control ] specify_terminal_descriptor
5436
   //    [ &&& timing_check_condition ]
5437

5438
   BEGIN("timing check event");
40✔
5439

5440
   if (scan(tEDGE, tPOSEDGE, tNEGEDGE))
20✔
5441
      p_timing_check_event_control();
4✔
5442

5443
   (void)p_specify_terminal_descriptor();
20✔
5444

5445
   if (optional(tTRPLAMP))
20✔
5446
      p_timing_check_condition();
4✔
5447

5448
   return NULL;
20✔
5449
}
5450

5451
static vlog_node_t p_controlled_timing_check_event(void)
4✔
5452
{
5453
   // timing_check_event_control specify_terminal_descriptor
5454
   //    [ &&& timing_check_condition ]
5455

5456
   BEGIN("controlled timing check event");
8✔
5457

5458
   p_timing_check_event_control();
4✔
5459

5460
   (void)p_specify_terminal_descriptor();
4✔
5461

5462
   if (optional(tTRPLAMP))
4✔
UNCOV
5463
      p_timing_check_condition();
×
5464

5465
   return NULL;
4✔
5466
}
5467

5468
static vlog_node_t p_setup_or_hold_timing_check(void)
6✔
5469
{
5470
   // $setup ( data_event , reference_event , timing_check_limit
5471
   //   [ , [ notifier ] ] ) ;
5472
   //
5473
   // $hold ( reference_event , data_event , timing_check_limit
5474
   //   [ , [ notifier ] ] ) ;
5475

5476
   BEGIN("setup/hold timing check");
12✔
5477

5478
   one_of(tDLRSETUP, tDLRHOLD);
6✔
5479
   consume(tLPAREN);
6✔
5480

5481
   (void)p_timing_check_event();
6✔
5482

5483
   consume(tCOMMA);
6✔
5484

5485
   (void)p_timing_check_event();
6✔
5486

5487
   consume(tCOMMA);
6✔
5488

5489
   (void)p_expression();
6✔
5490

5491
   if (optional(tCOMMA)) {
6✔
5492
      if (peek() == tID)
4✔
5493
         p_identifier();
2✔
5494
   }
5495

5496
   consume(tRPAREN);
6✔
5497
   consume(tSEMI);
6✔
5498

5499
   return NULL;
6✔
5500
}
5501

5502
static vlog_node_t p_recovery_or_removal_timing_check(void)
2✔
5503
{
5504
   // $recovery ( reference_event , data_event , timing_check_limit
5505
   //   [ , [ notifier ] ] ) ;
5506
   //
5507
   // $removal ( reference_event , data_event , timing_check_limit
5508
   //   [ , [ notifier ] ] ) ;
5509

5510
   BEGIN("recovery/removal timing check");
4✔
5511

5512
   one_of(tDLRRECOVERY, tDLRREMOVAL);
2✔
5513
   consume(tLPAREN);
2✔
5514

5515
   (void)p_timing_check_event();
2✔
5516

5517
   consume(tCOMMA);
2✔
5518

5519
   (void)p_timing_check_event();
2✔
5520

5521
   consume(tCOMMA);
2✔
5522

5523
   (void)p_expression();
2✔
5524

5525
   if (optional(tCOMMA)) {
2✔
UNCOV
5526
      if (peek() == tID)
×
UNCOV
5527
         p_identifier();
×
5528
   }
5529

5530
   consume(tRPAREN);
2✔
5531
   consume(tSEMI);
2✔
5532

5533
   return NULL;
2✔
5534
}
5535

5536
static vlog_node_t p_width_timing_check(void)
1✔
5537
{
5538
   // $width ( controlled_reference_event , timing_check_limit , threshold
5539
   //   [ , [ notifier ] ] ) ;
5540

5541
   BEGIN("width timing check");
2✔
5542

5543
   consume(tDLRWIDTH);
1✔
5544
   consume(tLPAREN);
1✔
5545

5546
   (void)p_controlled_timing_check_event();
1✔
5547

5548
   consume(tCOMMA);
1✔
5549

5550
   (void)p_expression();
1✔
5551

5552
   consume(tCOMMA);
1✔
5553

5554
   (void)p_constant_expression();
1✔
5555

5556
   if (optional(tCOMMA)) {
1✔
UNCOV
5557
      if (peek() == tID)
×
UNCOV
5558
         p_identifier();
×
5559
   }
5560

5561
   consume(tRPAREN);
1✔
5562
   consume(tSEMI);
1✔
5563

5564
   return NULL;
1✔
5565
}
5566

5567
static vlog_node_t p_delayed_data_or_reference(void)
2✔
5568
{
5569
   // terminal_identifier
5570
   //   | terminal_identifier [ constant_mintypmax_expression ]
5571

5572
   BEGIN("delayed data/reference");
4✔
5573

5574
   p_identifier();
2✔
5575

5576
   return NULL;
2✔
5577
}
5578

5579
static vlog_node_t p_period_timing_check(void)
3✔
5580
{
5581
   // $period ( controlled_reference_event , timing_check_limit
5582
   //   [ , [ notifier ] ] ) ;
5583

5584
   BEGIN("period timing check");
6✔
5585

5586
   consume(tDLRPERIOD);
3✔
5587
   consume(tLPAREN);
3✔
5588

5589
   (void)p_controlled_timing_check_event();
3✔
5590

5591
   consume(tCOMMA);
3✔
5592

5593
   (void)p_expression();
3✔
5594

5595
   if (optional(tCOMMA)) {
3✔
5596
      if (peek() == tID)
2✔
5597
         p_identifier();
1✔
5598
   }
5599

5600
   consume(tRPAREN);
3✔
5601
   consume(tSEMI);
3✔
5602

5603
   return NULL;
3✔
5604
}
5605

5606
static vlog_node_t p_setuphold_or_recrem_timing_check(void)
2✔
5607
{
5608
   // $setuphold ( reference_event , data_event , timing_check_limit ,
5609
   //    timing_check_limit [ , [ notifier ] [ , [ timestamp_condition ]
5610
   //    [ , [ timecheck_condition ] [ , [ delayed_reference ]
5611
   //    [ , [ delayed_data ] ] ] ] ] ] ) ;
5612

5613
   BEGIN("setuphold/recrem timing check");
4✔
5614

5615
   one_of(tDLRSETUPHOLD, tDLRRECREM);
2✔
5616
   consume(tLPAREN);
2✔
5617

5618
   (void)p_timing_check_event();
2✔
5619

5620
   consume(tCOMMA);
2✔
5621

5622
   (void)p_timing_check_event();
2✔
5623

5624
   consume(tCOMMA);
2✔
5625

5626
   (void)p_expression();
2✔
5627

5628
   consume(tCOMMA);
2✔
5629

5630
   (void)p_expression();
2✔
5631

5632
   if (optional(tCOMMA)) {
2✔
5633
      if (peek() == tID)
2✔
5634
         p_identifier(); // notifier
2✔
5635

5636
      if (optional(tCOMMA)) {
2✔
5637
         if (not_at_token(tCOMMA, tRPAREN))
2✔
UNCOV
5638
            (void)p_mintypmax_expression();  // timestamp_condition
×
5639

5640
         if (optional(tCOMMA)) {
2✔
5641
            if (not_at_token(tCOMMA, tRPAREN))
2✔
UNCOV
5642
               (void)p_mintypmax_expression();  // timecheck_condition
×
5643

5644
            if (optional(tCOMMA)) {
2✔
5645
               if (not_at_token(tCOMMA, tRPAREN))
2✔
5646
                  p_delayed_data_or_reference();  // delayed_reference
1✔
5647

5648
               if (optional(tCOMMA)) {
2✔
5649
                  if (not_at_token(tCOMMA, tRPAREN))
2✔
5650
                     p_delayed_data_or_reference();  // delayed_data
1✔
5651
               }
5652
            }
5653
         }
5654
      }
5655
   }
5656

5657
   consume(tRPAREN);
2✔
5658
   consume(tSEMI);
2✔
5659

5660
   return NULL;
2✔
5661
}
5662

5663
static vlog_node_t p_system_timing_check(void)
14✔
5664
{
5665
   // $setup_timing_check | $hold_timing_check | $setuphold_timing_check
5666
   //   | $recovery_timing_check | $removal_timing_check | $recrem_timing_check
5667
   //   | $skew_timing_check | $timeskew_timing_check | $fullskew_timing_check
5668
   //   | $period_timing_check | $width_timing_check | $nochange_timing_check
5669

5670
   BEGIN("system timing check");
28✔
5671

5672
   switch (peek()) {
14✔
5673
   case tDLRSETUP:
6✔
5674
   case tDLRHOLD:
5675
      return p_setup_or_hold_timing_check();
6✔
5676
   case tDLRRECOVERY:
2✔
5677
   case tDLRREMOVAL:
5678
      return p_recovery_or_removal_timing_check();
2✔
5679
   case tDLRWIDTH:
1✔
5680
      return p_width_timing_check();
1✔
5681
   case tDLRPERIOD:
3✔
5682
      return p_period_timing_check();
3✔
5683
   case tDLRSETUPHOLD:
2✔
5684
   case tDLRRECREM:
5685
      return p_setuphold_or_recrem_timing_check();
2✔
UNCOV
5686
   default:
×
5687
      should_not_reach_here();
5688
   }
5689
}
5690

5691
static vlog_node_t p_pulse_control_specparam(void)
1✔
5692
{
5693
   // PATHPULSE$ = (reject_limit_value [, error_limit_value])
5694
   //   | PATHPULSE$specify_input_terminal_descriptor
5695
   //       $specify_output_terminal_descriptor =
5696
   //       (reject_limit_value [, error_limit_value])
5697

5698
   BEGIN("pulse control specparam");
2✔
5699

5700
   vlog_node_t v = vlog_new(V_SPECPARAM);
1✔
5701

5702
   consume(tPATHPULSE);
1✔
5703

5704
   consume(tEQ);
1✔
5705
   consume(tLPAREN);
1✔
5706

5707
   vlog_set_value(v, p_constant_mintypmax_expression());
1✔
5708

5709
   if (optional(tCOMMA))
1✔
5710
      (void)p_constant_mintypmax_expression();
1✔
5711

5712
   consume(tRPAREN);
1✔
5713

5714
   vlog_set_loc(v, CURRENT_LOC);
1✔
5715
   return v;
1✔
5716
}
5717

5718
static vlog_node_t p_specparam_assignment(void)
4✔
5719
{
5720
   // specparam_identifier = constant_mintypmax_expression
5721
   //   | pulse_control_specparam
5722

5723
   BEGIN("specparam assignment");
8✔
5724

5725
   if (peek() == tPATHPULSE)
4✔
5726
      return p_pulse_control_specparam();
1✔
5727
   else {
5728
      vlog_node_t v = vlog_new(V_SPECPARAM);
3✔
5729
      vlog_set_ident(v, p_identifier());
3✔
5730

5731
      consume(tEQ);
3✔
5732

5733
      vlog_set_value(v, p_constant_mintypmax_expression());
3✔
5734

5735
      vlog_set_loc(v, CURRENT_LOC);
3✔
5736
      vlog_symtab_put(symtab, v);
3✔
5737
      return v;
3✔
5738
   }
5739
}
5740

5741
static void p_list_of_specparam_assignments(vlog_node_t parent)
4✔
5742
{
5743
   // specparam_assignment { , specparam_assignment }
5744

5745
   BEGIN("list of specparam assignments");
8✔
5746

5747
   do {
4✔
5748
      vlog_add_decl(parent, p_specparam_assignment());
4✔
5749
   } while (optional(tCOMMA));
4✔
5750
}
4✔
5751

5752
static void p_specparam_declaration(vlog_node_t parent)
4✔
5753
{
5754
   // specparam [ packed_dimension ] list_of_specparam_assignments ;
5755

5756
   BEGIN("specparam declaration");
8✔
5757

5758
   consume(tSPECPARAM);
4✔
5759

5760
   if (peek() == tLSQUARE)
4✔
5761
      (void)p_packed_dimension();
1✔
5762

5763
   p_list_of_specparam_assignments(parent);
4✔
5764

5765
   consume(tSEMI);
4✔
5766
}
4✔
5767

5768
static void p_specify_item(vlog_node_t parent)
36✔
5769
{
5770
   // specparam_declaration | pulsestyle_declaration | showcancelled_declaration
5771
   //   | path_declaration | system_timing_check
5772

5773
   BEGIN("specify item");
72✔
5774

5775
   switch (peek()) {
36✔
5776
   case tSPECPARAM:
4✔
5777
      p_specparam_declaration(parent);
4✔
5778
      break;
4✔
5779
   case tLPAREN:
18✔
5780
   case tIF:
5781
   case tIFNONE:
5782
      (void)p_path_declaration();
18✔
5783
      break;
18✔
5784
   case tDLRSETUP:
14✔
5785
   case tDLRHOLD:
5786
   case tDLRRECOVERY:
5787
   case tDLRREMOVAL:
5788
   case tDLRSETUPHOLD:
5789
   case tDLRRECREM:
5790
   case tDLRWIDTH:
5791
   case tDLRPERIOD:
5792
      (void)p_system_timing_check();
14✔
5793
      break;
14✔
UNCOV
5794
   default:
×
UNCOV
5795
      one_of(tSPECPARAM, tLPAREN, tIF, tIFNONE, tDLRSETUP, tDLRHOLD,
×
5796
             tDLRRECOVERY, tDLRREMOVAL, tDLRSETUPHOLD, tDLRRECREM,
5797
             tDLRWIDTH, tDLRPERIOD);
5798
   }
5799
}
36✔
5800

5801
static vlog_node_t p_specify_block(void)
3✔
5802
{
5803
   // specify { specify_item } endspecify
5804

5805
   BEGIN("specify block");
6✔
5806

5807
   consume(tSPECIFY);
3✔
5808

5809
   vlog_node_t v = vlog_new(V_SPECIFY);
3✔
5810
   vlog_set_loc(v, CURRENT_LOC);
3✔
5811

5812
   vlog_symtab_push(symtab, v);
3✔
5813

5814
   while (not_at_token(tENDSPECIFY))
39✔
5815
      p_specify_item(v);
36✔
5816

5817
   vlog_symtab_pop(symtab);
3✔
5818

5819
   consume(tENDSPECIFY);
3✔
5820

5821
   vlog_set_loc(v, CURRENT_LOC);
3✔
5822
   return v;
3✔
5823
}
5824

5825
static vlog_node_t p_ordered_port_connection(void)
275✔
5826
{
5827
   // { attribute_instance } [ expression ]
5828

5829
   BEGIN("ordered port connection");
550✔
5830

5831
   optional_attributes();
275✔
5832

5833
   vlog_node_t v = vlog_new(V_PORT_CONN);
275✔
5834

5835
   if (not_at_token(tCOMMA, tRPAREN))
275✔
5836
      vlog_set_value(v, p_expression());
275✔
5837

5838
   vlog_set_loc(v, CURRENT_LOC);
275✔
5839
   return v;
275✔
5840
}
5841

5842
static vlog_node_t p_named_port_connection(void)
159✔
5843
{
5844
   // { attribute_instance } . port_identifier [ ( [ expression ] ) ]
5845
   //    | { attribute_instance } .*
5846

5847
   BEGIN("named port connection");
318✔
5848

5849
   optional_attributes();
159✔
5850

5851
   vlog_node_t v = vlog_new(V_PORT_CONN);
159✔
5852

5853
   consume(tDOT);
159✔
5854

5855
   vlog_set_ident(v, p_identifier());
159✔
5856

5857
   if (optional(tLPAREN)) {
159✔
5858

5859
      if (peek() != tRPAREN)
159✔
5860
         vlog_set_value(v, p_expression());
157✔
5861

5862
      consume(tRPAREN);
159✔
5863
   }
5864

5865
   vlog_set_loc(v, CURRENT_LOC);
159✔
5866
   return v;
159✔
5867
}
5868

5869
static void p_list_of_port_connections(vlog_node_t inst)
188✔
5870
{
5871
   // ordered_port_connection { , ordered_port_connection }
5872
   //   | named_port_connection { , named_port_connection }
5873

5874
   BEGIN("list of port connections");
376✔
5875

5876
   vlog_symtab_set_implicit(symtab, implicit_kind);
188✔
5877

5878
   do {
434✔
5879
      skip_over_attributes();
434✔
5880

5881
      if (peek() == tDOT)
434✔
5882
         vlog_add_param(inst, p_named_port_connection());
159✔
5883
      else
5884
         vlog_add_param(inst, p_ordered_port_connection());
275✔
5885
   } while (optional(tCOMMA));
434✔
5886

5887
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
188✔
5888
}
188✔
5889

5890
static vlog_node_t p_hierarchical_instance(void)
184✔
5891
{
5892
   // name_of_instance ( [ list_of_port_connections ] )
5893

5894
   BEGIN("hierarchical instance");
368✔
5895

5896
   vlog_node_t v = vlog_new(V_MOD_INST);
184✔
5897
   vlog_set_ident(v, p_identifier());
184✔
5898

5899
   consume(tLPAREN);
184✔
5900

5901
   if (peek() != tRPAREN)
184✔
5902
      p_list_of_port_connections(v);
171✔
5903

5904
   consume(tRPAREN);
184✔
5905

5906
   vlog_set_loc(v, CURRENT_LOC);
184✔
5907
   vlog_symtab_put(symtab, v);
184✔
5908
   return v;
184✔
5909
}
5910

5911
static vlog_node_t p_udp_instance(void)
17✔
5912
{
5913
   // [ name_of_instance ] ( output_terminal , input_terminal
5914
   //   { , input_terminal } )
5915

5916
   BEGIN("udp instance");
34✔
5917

5918
   vlog_node_t v = vlog_new(V_MOD_INST);
17✔
5919
   if (peek() == tID)
17✔
UNCOV
5920
      vlog_set_ident(v, p_identifier());
×
5921
   else
5922
      vlog_set_ident(v, ident_uniq("$unnamed"));
17✔
5923

5924
   consume(tLPAREN);
17✔
5925

5926
   p_list_of_port_connections(v);
17✔
5927

5928
   consume(tRPAREN);
17✔
5929

5930
   vlog_set_loc(v, CURRENT_LOC);
17✔
5931
   return v;
17✔
5932
}
5933

5934
static vlog_node_t p_param_expression(void)
66✔
5935
{
5936
   // mintypmax_expression | data_type | $
5937

5938
   BEGIN("param expression");
132✔
5939

5940
   return p_expression();   // TODO
66✔
5941
}
5942

5943
static vlog_node_t p_named_parameter_assignment(void)
18✔
5944
{
5945
   // . parameter_identifier ( [ param_expression ] )
5946

5947
   BEGIN("named parameter assignment");
36✔
5948

5949
   consume(tDOT);
18✔
5950

5951
   vlog_node_t v = vlog_new(V_PARAM_ASSIGN);
18✔
5952
   vlog_set_ident(v, p_identifier());
18✔
5953

5954
   consume(tLPAREN);
18✔
5955

5956
   if (peek() != tRPAREN)
18✔
5957
      vlog_set_value(v, p_param_expression());
14✔
5958

5959
   consume(tRPAREN);
18✔
5960

5961
   vlog_set_loc(v, CURRENT_LOC);
18✔
5962
   return v;
18✔
5963
}
5964

5965
static vlog_node_t p_ordered_parameter_assignment(void)
52✔
5966
{
5967
   // param_expression
5968

5969
   BEGIN("ordered parameter assignment");
104✔
5970

5971
   vlog_node_t v = vlog_new(V_PARAM_ASSIGN);
52✔
5972
   vlog_set_value(v, p_param_expression());
52✔
5973

5974
   vlog_set_loc(v, CURRENT_LOC);
52✔
5975
   return v;
52✔
5976
}
5977

5978
static void p_list_of_parameter_assignments(vlog_node_t inst)
60✔
5979
{
5980
   // ordered_parameter_assignment { , ordered_parameter_assignment }
5981
   //   | named_parameter_assignment { , named_parameter_assignment }
5982

5983
   BEGIN("list of parameter assignments");
120✔
5984

5985
   do {
70✔
5986
      if (peek() == tDOT)
70✔
5987
         vlog_add_param(inst, p_named_parameter_assignment());
18✔
5988
      else
5989
         vlog_add_param(inst, p_ordered_parameter_assignment());
52✔
5990
   } while (optional(tCOMMA));
70✔
5991
}
60✔
5992

5993
static void p_parameter_value_assignment(vlog_node_t inst)
60✔
5994
{
5995
   // # ( [ list_of_parameter_assignments ] )
5996

5997
   BEGIN("parameter value assignment");
120✔
5998

5999
   consume(tHASH);
60✔
6000
   consume(tLPAREN);
60✔
6001

6002
   if (peek() != tRPAREN)
60✔
6003
      p_list_of_parameter_assignments(inst);
60✔
6004

6005
   consume(tRPAREN);
60✔
6006
}
60✔
6007

6008
static void p_module_or_udp_instantiation(vlog_node_t mod)
195✔
6009
{
6010
   // module_identifier [ parameter_value_assignment ] hierarchical_instance
6011
   //   { , hierarchical_instance } ;
6012
   //
6013
   // udp_identifier [ drive_strength ] [ delay2 ] udp_instance
6014
   //   { , udp_instance } ;
6015

6016
   BEGIN("module instantiation");
390✔
6017

6018
   vlog_node_t v = vlog_new(V_INST_LIST);
195✔
6019
   vlog_set_ident(v, p_identifier());
195✔
6020

6021
   if (peek() == tHASH)
195✔
6022
      p_parameter_value_assignment(v);
60✔
6023

6024
   do {
201✔
6025
      if (peek() == tLPAREN)
201✔
6026
         vlog_add_stmt(v, p_udp_instance());
17✔
6027
      else
6028
         vlog_add_stmt(v, p_hierarchical_instance());
184✔
6029
   } while (optional(tCOMMA));
201✔
6030

6031
   consume(tSEMI);
195✔
6032

6033
   vlog_set_loc(v, CURRENT_LOC);
195✔
6034

6035
   vlog_add_stmt(mod, v);
195✔
6036
}
195✔
6037

6038
static vlog_node_t p_defparam_assignment(void)
3✔
6039
{
6040
   // hierarchical_parameter_identifier = constant_mintypmax_expression
6041

6042
   BEGIN("defparam assignment");
6✔
6043

6044
   vlog_node_t v = vlog_new(V_DEFPARAM);
3✔
6045
   vlog_set_target(v, p_hierarchical_identifier(NULL));
3✔
6046

6047
   consume(tEQ);
3✔
6048

6049
   vlog_set_value(v, p_constant_mintypmax_expression());
3✔
6050

6051
   vlog_set_loc(v, CURRENT_LOC);
3✔
6052
   return v;
3✔
6053
}
6054

6055
static void p_list_of_defparam_assignments(vlog_node_t parent)
3✔
6056
{
6057
   // defparam_assignment { , defparam_assignment }
6058

6059
   BEGIN("list of defparam assignments");
6✔
6060

6061
   do {
3✔
6062
      vlog_add_stmt(parent, p_defparam_assignment());
3✔
6063
   } while (optional(tCOMMA));
3✔
6064
}
3✔
6065

6066
static void p_parameter_override(vlog_node_t parent)
3✔
6067
{
6068
   // defparam list_of_defparam_assignments ;
6069

6070
   BEGIN("parameter override");
6✔
6071

6072
   consume(tDEFPARAM);
3✔
6073

6074
   p_list_of_defparam_assignments(parent);
3✔
6075

6076
   consume(tSEMI);
3✔
6077
}
3✔
6078

6079
static void p_module_or_generate_item(vlog_node_t mod)
7,586✔
6080
{
6081
   // { attribute_instance } parameter_override
6082
   //   | { attribute_instance } gate_instantiation
6083
   //   | { attribute_instance } udp_instantiation
6084
   //   | { attribute_instance } module_instantiation
6085
   //   | { attribute_instance } module_common_item
6086

6087
   BEGIN("module or generate item");
15,172✔
6088

6089
   optional_attributes();
7,586✔
6090

6091
   switch (peek()) {
7,586✔
6092
   case tALWAYS:
7,276✔
6093
   case tALWAYSCOMB:
6094
   case tALWAYSFF:
6095
   case tALWAYSLATCH:
6096
   case tWIRE:
6097
   case tUWIRE:
6098
   case tSUPPLY0:
6099
   case tSUPPLY1:
6100
   case tTRI:
6101
   case tTRI0:
6102
   case tTRI1:
6103
   case tTRIAND:
6104
   case tTRIOR:
6105
   case tTRIREG:
6106
   case tWAND:
6107
   case tWOR:
6108
   case tINTERCONNECT:
6109
   case tREG:
6110
   case tSTRUCT:
6111
   case tUNION:
6112
   case tASSIGN:
6113
   case tINITIAL:
6114
   case tTYPEDEF:
6115
   case tENUM:
6116
   case tSVINT:
6117
   case tINTEGER:
6118
   case tSVREAL:
6119
   case tSHORTREAL:
6120
   case tREALTIME:
6121
   case tTIME:
6122
   case tTASK:
6123
   case tFUNCTION:
6124
   case tLOCALPARAM:
6125
   case tPARAMETER:
6126
   case tIF:
6127
   case tCASE:
6128
   case tFOR:
6129
   case tEVENT:
6130
   case tGENVAR:
6131
   case tVAR:
6132
   case tLOGIC:
6133
   case tBIT:
6134
   case tSHORTINT:
6135
   case tLONGINT:
6136
   case tBYTE:
6137
   case tSTRINGK:
6138
   case tIMPORT:
6139
   case tFINAL:
6140
      p_module_common_item(mod);
7,276✔
6141
      break;
7,276✔
6142
   case tPULLDOWN:
88✔
6143
   case tPULLUP:
6144
   case tAND:
6145
   case tNAND:
6146
   case tOR:
6147
   case tNOR:
6148
   case tXOR:
6149
   case tXNOR:
6150
   case tNOT:
6151
   case tBUF:
6152
   case tBUFIF0:
6153
   case tBUFIF1:
6154
   case tNOTIF0:
6155
   case tNOTIF1:
6156
   case tTRAN:
6157
   case tTRANIF0:
6158
   case tTRANIF1:
6159
   case tRTRAN:
6160
   case tRTRANIF0:
6161
   case tRTRANIF1:
6162
      p_gate_instantiation(mod);
88✔
6163
      break;
88✔
6164
   case tDEFPARAM:
3✔
6165
      p_parameter_override(mod);
3✔
6166
      break;
3✔
6167
   case tID:
219✔
6168
      {
6169
         vlog_node_t ref = peek_reference();
219✔
6170
         if (ref == NULL)
219✔
6171
            p_module_or_udp_instantiation(mod);
195✔
6172
         else
6173
            p_module_common_item(mod);
24✔
6174
      }
6175
      break;
UNCOV
6176
   default:
×
UNCOV
6177
      expect(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
×
6178
             tSUPPLY0, tSUPPLY1, tTRI,  tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
6179
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tASSIGN,
6180
             tINITIAL, tTYPEDEF, tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL,
6181
             tREALTIME, tTIME, tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER, tIF,
6182
             tFOR, tEVENT, tGENVAR, tVAR, tLOGIC, tBIT, tSHORTINT, tLONGINT,
6183
             tBYTE, tSTRINGK, tIMPORT, tFINAL, tPULLDOWN, tPULLUP, tID, tAND,
6184
             tNAND, tOR, tNOR, tXOR, tXNOR, tNOT, tBUF, tBUFIF0, tBUFIF1,
6185
             tNOTIF0, tNOTIF1, tDEFPARAM, tID);
UNCOV
6186
      drop_tokens_until(&state, tSEMI);
×
6187
   }
6188
}
7,586✔
6189

6190
static void p_generate_region(vlog_node_t mod)
20✔
6191
{
6192
   // generate { generate_item } endgenerate
6193

6194
   BEGIN("generate region");
40✔
6195

6196
   // Has no real meaning in System Verilog
6197

6198
   // TODO: generate regions do not nest so check mod is V_MODULE
6199

6200
   consume(tGENERATE);
20✔
6201

6202
   if (optional(tBEGIN)) {
20✔
6203
      // This is non-standard but seen in some legacy code
6204
      consume(tCOLON);
1✔
6205

6206
      vlog_node_t b = vlog_new(V_BLOCK);
1✔
6207
      vlog_set_ident(b, p_identifier());
1✔
6208

6209
      while (not_at_token(tEND))
1✔
UNCOV
6210
         p_generate_item(b);
×
6211

6212
      consume(tEND);
1✔
6213

6214
      vlog_set_loc(b, CURRENT_LOC);
1✔
6215
      vlog_add_stmt(mod, b);
1✔
6216
   }
6217
   else {
6218
      while (not_at_token(tENDGENERATE))
38✔
6219
         p_generate_item(mod);
19✔
6220
   }
6221

6222
   consume(tENDGENERATE);
20✔
6223
}
20✔
6224

6225
static void p_non_port_module_item(vlog_node_t mod)
7,477✔
6226
{
6227
   // generate_region | module_or_generate_item | specify_block
6228
   //   | { attribute_instance } specparam_declaration | program_declaration
6229
   //   | module_declaration | interface_declaration | timeunits_declaration
6230

6231
   BEGIN("non-port module item");
14,954✔
6232

6233
   switch (peek()) {
7,477✔
6234
   case tALWAYS:
7,452✔
6235
   case tALWAYSCOMB:
6236
   case tALWAYSFF:
6237
   case tALWAYSLATCH:
6238
   case tWIRE:
6239
   case tUWIRE:
6240
   case tSUPPLY0:
6241
   case tSUPPLY1:
6242
   case tTRI:
6243
   case tTRI0:
6244
   case tTRI1:
6245
   case tTRIAND:
6246
   case tTRIOR:
6247
   case tTRIREG:
6248
   case tWAND:
6249
   case tWOR:
6250
   case tINTERCONNECT:
6251
   case tREG:
6252
   case tSTRUCT:
6253
   case tUNION:
6254
   case tASSIGN:
6255
   case tINITIAL:
6256
   case tPULLDOWN:
6257
   case tPULLUP:
6258
   case tID:
6259
   case tATTRBEGIN:
6260
   case tAND:
6261
   case tNAND:
6262
   case tOR:
6263
   case tNOR:
6264
   case tXOR:
6265
   case tXNOR:
6266
   case tNOT:
6267
   case tBUF:
6268
   case tBUFIF0:
6269
   case tBUFIF1:
6270
   case tNOTIF0:
6271
   case tNOTIF1:
6272
   case tTRAN:
6273
   case tTRANIF0:
6274
   case tTRANIF1:
6275
   case tRTRAN:
6276
   case tRTRANIF0:
6277
   case tRTRANIF1:
6278
   case tTYPEDEF:
6279
   case tENUM:
6280
   case tSVINT:
6281
   case tINTEGER:
6282
   case tSVREAL:
6283
   case tSHORTREAL:
6284
   case tREALTIME:
6285
   case tTIME:
6286
   case tTASK:
6287
   case tFUNCTION:
6288
   case tLOCALPARAM:
6289
   case tPARAMETER:
6290
   case tEVENT:
6291
   case tIF:
6292
   case tFOR:
6293
   case tGENVAR:
6294
   case tVAR:
6295
   case tLOGIC:
6296
   case tBIT:
6297
   case tSHORTINT:
6298
   case tLONGINT:
6299
   case tBYTE:
6300
   case tSTRINGK:
6301
   case tIMPORT:
6302
   case tDEFPARAM:
6303
   case tFINAL:
6304
      p_module_or_generate_item(mod);
7,452✔
6305
      break;
7,452✔
6306
   case tSPECIFY:
3✔
6307
      vlog_add_stmt(mod, p_specify_block());
3✔
6308
      break;
3✔
6309
   case tGENERATE:
20✔
6310
      p_generate_region(mod);
20✔
6311
      break;
20✔
6312
   default:
2✔
6313
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
2✔
6314
             tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
6315
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tASSIGN,
6316
             tPULLDOWN, tPULLUP, tID, tATTRBEGIN, tAND, tNAND, tOR, tNOR, tXOR,
6317
             tXNOR, tNOT, tBUF, tBUFIF0, tBUFIF1, tNOTIF0, tNOTIF1, tTYPEDEF,
6318
             tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTIME,
6319
             tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER, tEVENT, tIF, tFOR,
6320
             tGENVAR, tVAR, tLOGIC, tBIT, tSHORTINT, tLONGINT, tBYTE, tSTRINGK,
6321
             tIMPORT, tDEFPARAM, tFINAL, tSPECIFY, tGENERATE);
6322
      drop_tokens_until(&state, tSEMI);
2✔
6323
   }
6324
}
7,477✔
6325

6326
static void p_module_item(vlog_node_t mod)
7,917✔
6327
{
6328
   // port_declaration ; | non_port_module_item
6329

6330
   BEGIN("module item");
15,834✔
6331

6332
   skip_over_attributes();
7,917✔
6333

6334
   if (scan(tINOUT, tINPUT, tOUTPUT)) {
7,917✔
6335
      p_port_declaration(mod);
440✔
6336
      consume(tSEMI);
440✔
6337
   }
6338
   else
6339
      p_non_port_module_item(mod);
7,477✔
6340
}
7,917✔
6341

6342
static void p_ansi_port_declaration(vlog_node_t mod, v_port_kind_t *kind,
155✔
6343
                                    vlog_node_t *dt)
6344
{
6345
   // [ net_port_header | interface_port_header ] port_identifier
6346
   //     { unpacked_dimension } [ = constant_expression ]
6347
   // | [ variable_port_header ] port_identifier { variable_dimension }
6348
   //     [ = constant_expression ]
6349
   // | [ port_direction ] . port_identifier ( [ expression ] )
6350

6351
   BEGIN("ANSI port declaration");
310✔
6352

6353
   if (peek() != tID)
155✔
6354
      p_net_port_header(kind, dt);
133✔
6355
   else if (*dt == NULL)
22✔
UNCOV
6356
      *dt = implicit_type();
×
6357

6358
   ident_t id, ext;
155✔
6359
   p_external_identifier(&id, &ext);
155✔
6360

6361
   vlog_node_t v = vlog_new(V_PORT_DECL);
155✔
6362
   vlog_set_subkind(v, *kind);
155✔
6363
   vlog_set_ident(v, id);
155✔
6364
   vlog_set_ident2(v, ext);
155✔
6365
   vlog_set_type(v, *dt);
155✔
6366
   vlog_set_loc(v, &state.last_loc);
155✔
6367

6368
   if (optional(tEQ))
155✔
6369
      vlog_set_value(v, p_constant_expression());
9✔
6370

6371
   vlog_add_decl(mod, v);
155✔
6372
   vlog_symtab_put(symtab, v);
155✔
6373

6374
   vlog_node_t ref = vlog_new(V_REF);
155✔
6375
   vlog_set_loc(ref, CURRENT_LOC);
155✔
6376
   vlog_set_ident(ref, id);
155✔
6377
   vlog_set_ref(ref, v);
155✔
6378

6379
   vlog_add_port(mod, ref);
155✔
6380
}
155✔
6381

6382
static void p_list_of_port_declarations(vlog_node_t mod)
166✔
6383
{
6384
   // ( [ { attribute_instance } ansi_port_declaration
6385
   //   { , { attribute_instance } ansi_port_declaration } ] )
6386

6387
   BEGIN("list of port declarations");
332✔
6388

6389
   consume(tLPAREN);
166✔
6390

6391
   if (peek() != tRPAREN) {
166✔
6392
      v_port_kind_t kind = V_PORT_INPUT;
62✔
6393
      vlog_node_t dt = NULL;
62✔
6394
      do {
155✔
6395
         optional_attributes();
155✔
6396
         p_ansi_port_declaration(mod, &kind, &dt);
155✔
6397
      } while (optional(tCOMMA));
155✔
6398
   }
6399

6400
   consume(tRPAREN);
166✔
6401
}
166✔
6402

6403
static void p_parameter_port_declaration(vlog_node_t mod)
53✔
6404
{
6405
   // parameter_declaration
6406
   //    | local_parameter_declaration
6407
   //    | data_type list_of_param_assignments
6408
   //    | type list_of_type_assignments
6409

6410
   BEGIN("parameter port declaration");
106✔
6411

6412
   switch (peek()) {
53✔
6413
   case tPARAMETER:
47✔
6414
      p_parameter_declaration(mod);
47✔
6415
      break;
47✔
6416
   case tLOCALPARAM:
5✔
6417
      p_local_parameter_declaration(mod);
5✔
6418
      break;
5✔
6419
   default:
1✔
6420
      // TODO: Add parsing of "type" declarations example #(type T = bit)
6421
      {
6422
         vlog_node_t datatype = p_data_type();
1✔
6423
         p_list_of_param_assignments(mod, datatype, V_PARAM_DECL);
1✔
6424
      }
6425
      break;
1✔
6426
   }
6427
}
53✔
6428

6429
static void p_parameter_port_list(vlog_node_t mod)
27✔
6430
{
6431
   // # ( list_of_param_assignments { , parameter_port_declaration } )
6432
   //    | # ( parameter_port_declaration { , parameter_port_declaration } )
6433
   //    | # ( )
6434

6435
   BEGIN("parameter port list");
54✔
6436

6437
   consume(tHASH);
27✔
6438
   consume(tLPAREN);
27✔
6439

6440
   if (peek() != tRPAREN) {
27✔
6441
      do {
54✔
6442
         if (peek() == tID)
54✔
6443
            p_list_of_param_assignments(mod, implicit_type(), V_PARAM_DECL);
1✔
6444
         else
6445
            p_parameter_port_declaration(mod);
53✔
6446
      } while(optional(tCOMMA));
54✔
6447
   }
6448

6449
   consume(tRPAREN);
27✔
6450
}
27✔
6451

6452
static void p_module_ansi_header(vlog_node_t mod)
853✔
6453
{
6454
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
6455
   //    { package_import_declaration } [ parameter_port_list ]
6456
   ///   [ list_of_port_declarations ] ;
6457

6458
   EXTEND("module ANSI header");
1,706✔
6459

6460
   if (peek() == tLPAREN)
853✔
6461
      p_list_of_port_declarations(mod);
166✔
6462

6463
   consume(tSEMI);
853✔
6464

6465
   vlog_set_loc(mod, CURRENT_LOC);
853✔
6466
}
853✔
6467

6468
static vlog_node_t p_port_reference(void)
470✔
6469
{
6470
   // port_identifier constant_select
6471

6472
   BEGIN("port reference");
940✔
6473

6474
   vlog_node_t v = vlog_new(V_REF);
470✔
6475
   vlog_set_ident(v, p_identifier());
470✔
6476
   vlog_set_loc(v, CURRENT_LOC);
470✔
6477
   return v;
470✔
6478
}
6479

6480
static vlog_node_t p_port_expression(void)
470✔
6481
{
6482
   // port_reference | { port_reference { , port_reference } }
6483

6484
   BEGIN("port expression");
940✔
6485

6486
   return p_port_reference();
470✔
6487
}
6488

6489
static vlog_node_t p_port(void)
470✔
6490
{
6491
   // [ port_expression ] | . port_identifier ( [ port_expression ] )
6492

6493
   BEGIN("port");
940✔
6494

6495
   return p_port_expression();
470✔
6496
}
6497

6498
static void p_list_of_ports(vlog_node_t mod)
156✔
6499
{
6500
   // ( port { , port } )
6501

6502
   BEGIN("list of ports");
312✔
6503

6504
   consume(tLPAREN);
156✔
6505

6506
   do {
470✔
6507
      vlog_add_port(mod, p_port());
470✔
6508
   } while (optional(tCOMMA));
470✔
6509

6510
   consume(tRPAREN);
156✔
6511
}
156✔
6512

6513
static void p_module_nonansi_header(vlog_node_t mod)
156✔
6514
{
6515
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
6516
   //    { package_import_declaration } [ parameter_port_list ] list_of_ports ;
6517

6518
   EXTEND("module non-ANSI header");
312✔
6519

6520
   p_list_of_ports(mod);
156✔
6521

6522
   consume(tSEMI);
156✔
6523

6524
   vlog_set_loc(mod, CURRENT_LOC);
156✔
6525
}
156✔
6526

6527
static vlog_node_t p_module_declaration(void)
1,009✔
6528
{
6529
   // module_nonansi_header [ timeunits_declaration ] { module_item }
6530
   //      endmodule [ : module_identifier ]
6531
   //   | module_ansi_header [ timeunits_declaration ] { non_port_module_item }
6532
   //      endmodule [ : module_identifier ]
6533
   //   | { attribute_instance } module_keyword [ lifetime ] module_identifier
6534
   //      ( .* ) ; [ timeunits_declaration ] { module_item } endmodule
6535
   //      [ : module_identifier ]
6536
   //   | extern module_nonansi_header
6537
   //   | extern module_ansi_header
6538

6539
   BEGIN("module declaration");
2,018✔
6540

6541
   vlog_node_t mod = vlog_new(V_MODULE);
1,009✔
6542

6543
   optional_attributes();
1,009✔
6544

6545
   consume(tMODULE);
1,009✔
6546

6547
   ident_t id, ext;
1,009✔
6548
   p_external_identifier(&id, &ext);
1,009✔
6549
   vlog_set_ident2(mod, id);
1,009✔
6550

6551
   vlog_set_loc(mod, &state.last_loc);
1,009✔
6552

6553
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
1,009✔
6554
   vlog_set_ident(mod, qual);
1,009✔
6555

6556
   vlog_symtab_push(symtab, mod);
1,009✔
6557

6558
   while (peek() == tIMPORT)
1,009✔
UNCOV
6559
      p_package_import_declaration(mod);
×
6560

6561
   if (peek() == tHASH) {
1,009✔
6562
      p_parameter_port_list(mod);
27✔
6563
      param_kind = V_LOCALPARAM;
27✔
6564
   }
6565

6566
   if (peek() == tLPAREN && peek_nth(2) == tID)
1,009✔
6567
      p_module_nonansi_header(mod);
156✔
6568
   else
6569
      p_module_ansi_header(mod);
853✔
6570

6571
   while (not_at_token(tENDMODULE))
8,926✔
6572
      p_module_item(mod);
7,917✔
6573

6574
   consume(tENDMODULE);
1,009✔
6575

6576
   if (optional(tCOLON)) {
1,009✔
6577
      ident_t name = p_identifier();
2✔
6578
      if (id != name)
2✔
6579
         error_at(&state.last_loc, "'%s' does not match module name '%s'",
1✔
6580
                  istr(name), istr(id));
6581
   }
6582

6583
   vlog_symtab_pop(symtab);
1,009✔
6584
   return mod;
1,009✔
6585
}
6586

6587
static void p_udp_port_list(vlog_node_t udp)
26✔
6588
{
6589
   // output_port_identifier , input_port_identifier { , input_port_identifier }
6590

6591
   BEGIN("UDP port list");
52✔
6592

6593
   vlog_node_t oref = vlog_new(V_REF);
26✔
6594
   vlog_set_ident(oref, p_identifier());
26✔
6595
   vlog_set_loc(oref, &state.last_loc);
26✔
6596

6597
   vlog_add_port(udp, oref);
26✔
6598

6599
   consume(tCOMMA);
26✔
6600

6601
   vlog_node_t iref = vlog_new(V_REF);
26✔
6602
   vlog_set_ident(iref, p_identifier());
26✔
6603
   vlog_set_loc(iref, &state.last_loc);
26✔
6604

6605
   vlog_add_port(udp, iref);
26✔
6606

6607
   while (optional(tCOMMA)) {
54✔
6608
      vlog_node_t iref = vlog_new(V_REF);
28✔
6609
      vlog_set_ident(iref, p_identifier());
28✔
6610
      vlog_set_loc(iref, &state.last_loc);
28✔
6611

6612
      vlog_add_port(udp, iref);
28✔
6613
   }
6614
}
26✔
6615

6616
static vlog_node_t p_udp_nonansi_declaration(void)
26✔
6617
{
6618
   // { attribute_instance } primitive udp_identifier ( udp_port_list ) ;
6619

6620
   BEGIN("UDP non-ANSI declaration");
52✔
6621

6622
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
26✔
6623

6624
   consume(tPRIMITIVE);
26✔
6625

6626
   ident_t id, ext;
26✔
6627
   p_external_identifier(&id, &ext);
26✔
6628
   vlog_set_ident2(udp, id);
26✔
6629

6630
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
26✔
6631
   vlog_set_ident(udp, qual);
26✔
6632

6633
   consume(tLPAREN);
26✔
6634

6635
   p_udp_port_list(udp);
26✔
6636

6637
   consume(tRPAREN);
26✔
6638
   consume(tSEMI);
26✔
6639

6640
   vlog_set_loc(udp, CURRENT_LOC);
26✔
6641
   return udp;
26✔
6642
}
6643

6644
static void p_list_of_udp_port_identifiers(vlog_node_t udp, v_port_kind_t kind)
39✔
6645
{
6646
   // port_identifier { , port_identifier }
6647

6648
   BEGIN("list of UDP port identifiers");
78✔
6649

6650
   do {
66✔
6651
      ident_t id, ext;
66✔
6652
      p_external_identifier(&id, &ext);
66✔
6653

6654
      vlog_node_t p = vlog_new(V_PORT_DECL);
66✔
6655
      vlog_set_subkind(p, kind);
66✔
6656
      vlog_set_ident(p, id);
66✔
6657
      vlog_set_ident2(p, ext);
66✔
6658
      vlog_set_type(p, implicit_type());
66✔
6659
      vlog_set_loc(p, &state.last_loc);
66✔
6660

6661
      vlog_add_decl(udp, p);
66✔
6662
      vlog_symtab_put(symtab, p);
66✔
6663
   } while (peek_nth(2) == tID && optional(tCOMMA));
66✔
6664
}
39✔
6665

6666
static void p_udp_output_declaration(vlog_node_t udp, bool *has_reg)
31✔
6667
{
6668
   // { attribute_instance } output port_identifier
6669
   //    | { attribute_instance } output reg port_identifier
6670
   //         [ = constant_expression ]
6671

6672
   BEGIN("UDP output declaration");
62✔
6673

6674
   consume(tOUTPUT);
31✔
6675

6676
   const bool isreg = optional(tREG);
31✔
6677

6678
   ident_t id, ext;
31✔
6679
   p_external_identifier(&id, &ext);
31✔
6680

6681
   vlog_node_t v = vlog_new(V_PORT_DECL);
31✔
6682
   vlog_set_subkind(v, V_PORT_OUTPUT);
31✔
6683
   vlog_set_ident(v, id);
31✔
6684
   vlog_set_ident2(v, ext);
31✔
6685
   vlog_set_loc(v, &state.last_loc);
31✔
6686

6687
   if (isreg) {
31✔
6688
      vlog_set_type(v, logic_type());
2✔
6689
      *has_reg = true;
2✔
6690
   }
6691
   else
6692
      vlog_set_type(v, implicit_type());
29✔
6693

6694
   vlog_add_decl(udp, v);
31✔
6695
   vlog_symtab_put(symtab, v);
31✔
6696
}
31✔
6697

6698
static void p_udp_input_declaration(vlog_node_t udp)
39✔
6699
{
6700
   // { attribute_instance } input list_of_udp_port_identifiers
6701

6702
   BEGIN("UDP input declaration");
78✔
6703

6704
   consume(tINPUT);
39✔
6705

6706
   p_list_of_udp_port_identifiers(udp, V_PORT_INPUT);
39✔
6707
}
39✔
6708

6709
static vlog_node_t p_udp_reg_declaration(void)
13✔
6710
{
6711
   // { attribute_instance } reg variable_identifier
6712

6713
   BEGIN("UDP reg declaration");
26✔
6714

6715
   consume(tREG);
13✔
6716

6717
   ident_t id = p_identifier();
13✔
6718

6719
   vlog_node_t reg = vlog_new(V_VAR_DECL);
13✔
6720
   vlog_set_loc(reg, &state.last_loc);
13✔
6721
   vlog_set_ident(reg, id);
13✔
6722
   vlog_set_type(reg, logic_type());
13✔
6723

6724
   return reg;
13✔
6725
}
6726

6727
static void p_udp_port_declaration(vlog_node_t udp, bool *has_reg)
65✔
6728
{
6729
   // udp_output_declaration ; | udp_input_declaration ; | udp_reg_declaration ;
6730

6731
   BEGIN("UDP port declaration");
130✔
6732

6733
   switch (peek()) {
65✔
6734
   case tOUTPUT:
26✔
6735
      p_udp_output_declaration(udp, has_reg);
26✔
6736
      break;
26✔
6737
   case tINPUT:
26✔
6738
      p_udp_input_declaration(udp);
26✔
6739
      break;
26✔
6740
   case tREG:
13✔
6741
      {
6742
         vlog_node_t v = p_udp_reg_declaration();
13✔
6743
         vlog_add_decl(udp, v);
13✔
6744
         vlog_symtab_put(symtab, v);
13✔
6745
         *has_reg = true;
13✔
6746
      }
6747
      break;
13✔
UNCOV
6748
   default:
×
UNCOV
6749
      one_of(tOUTPUT, tINPUT, tREG);
×
UNCOV
6750
      break;
×
6751
   }
6752

6753
   consume(tSEMI);
65✔
6754
}
65✔
6755

6756
static void p_udp_declaration_port_list(vlog_node_t udp, bool *has_reg)
5✔
6757
{
6758
   // udp_output_declaration , udp_input_declaration { , udp_input_declaration }
6759

6760
   BEGIN("UDP declaration port list");
10✔
6761

6762
   p_udp_output_declaration(udp, has_reg);
5✔
6763

6764
   consume(tCOMMA);
5✔
6765

6766
   do {
13✔
6767
      p_udp_input_declaration(udp);
13✔
6768
   } while (optional(tCOMMA));
13✔
6769

6770
   const int ndecls = vlog_decls(udp);
5✔
6771
   for (int i = 0; i < ndecls; i++) {
23✔
6772
      vlog_node_t p = vlog_decl(udp, i);
18✔
6773
      if (vlog_kind(p) != V_PORT_DECL)
18✔
UNCOV
6774
         continue;
×
6775

6776
      vlog_node_t ref = vlog_new(V_REF);
18✔
6777
      vlog_set_loc(ref, vlog_loc(p));
18✔
6778
      vlog_set_ident(ref, vlog_ident(p));
18✔
6779
      vlog_set_ref(ref, p);
18✔
6780

6781
      vlog_add_port(udp, ref);
18✔
6782
   }
6783
}
5✔
6784

6785
static vlog_node_t p_output_symbol(void)
129✔
6786
{
6787
   // 0 | 1 | x | X
6788

6789
   BEGIN("output symbol");
258✔
6790

6791
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
129✔
6792
   vlog_set_subkind(v, V_UDP_SYMBOL_OUTPUT);
129✔
6793

6794
   if (consume(tUDPLEVEL)) {
129✔
6795
      switch (state.last_lval.i64) {
129✔
6796
      case '0':
129✔
6797
      case '1':
6798
      case 'x':
6799
      case 'X':
6800
         vlog_set_ival(v, state.last_lval.i64);
129✔
6801
         break;
129✔
UNCOV
6802
      default:
×
UNCOV
6803
         parse_error(&state.last_loc, "'%c' is not a valid output symbol",
×
6804
                     (char)state.last_lval.i64);
6805
         break;
6806
      }
6807
   }
6808

6809
   vlog_set_loc(v, CURRENT_LOC);
129✔
6810
   return v;
129✔
6811
}
6812

6813
static vlog_node_t p_level_symbol(void)
509✔
6814
{
6815
   // 0 | 1 | x | X | ? | b | B
6816

6817
   BEGIN("level symbol");
1,018✔
6818

6819
   consume(tUDPLEVEL);
509✔
6820

6821
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
509✔
6822
   vlog_set_subkind(v, V_UDP_SYMBOL_INPUT);
509✔
6823
   vlog_set_ival(v, state.last_lval.i64);
509✔
6824

6825
   vlog_set_loc(v, CURRENT_LOC);
509✔
6826
   return v;
509✔
6827
}
6828

6829
static vlog_node_t p_next_state(void)
101✔
6830
{
6831
   // output_symbol | -
6832

6833
   BEGIN("next state");
202✔
6834

6835
   switch (peek()) {
101✔
6836
   case tMINUS:
35✔
6837
      consume(tMINUS);
35✔
6838
      break;
35✔
6839
   case tUDPLEVEL:
66✔
6840
      return p_output_symbol();
66✔
UNCOV
6841
   default:
×
UNCOV
6842
      one_of(tUDPLEVEL, tMINUS);
×
6843
   }
6844

6845
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
35✔
6846
   vlog_set_subkind(v, V_UDP_SYMBOL_OUTPUT);
35✔
6847
   vlog_set_ival(v, '-');
35✔
6848

6849
   vlog_set_loc(v, CURRENT_LOC);
35✔
6850
   return v;
35✔
6851
}
6852

6853
static vlog_node_t p_edge_symbol(void)
28✔
6854
{
6855
   // r | R | f | F | p | P | n | N | *
6856

6857
   BEGIN("edge symbol");
56✔
6858

6859
   consume(tUDPEDGE);
28✔
6860

6861
   char left, right;
28✔
6862
   switch (state.last_lval.i64) {
28✔
6863
   case 'r': case 'R': left = '0'; right = '1'; break;
UNCOV
6864
   case 'f': case 'F': left = '1'; right = '0'; break;
×
6865
   case 'p': case 'P': left = '?'; right = '1'; break;
8✔
6866
   case 'n': case 'N': left = '?'; right = '0'; break;
4✔
6867
   case '*':           left = '?'; right = '?'; break;
13✔
6868
   default: should_not_reach_here();
6869
   }
6870

6871
   vlog_node_t lsym = vlog_new(V_UDP_LEVEL);
28✔
6872
   vlog_set_ival(lsym, left);
28✔
6873

6874
   vlog_node_t rsym = vlog_new(V_UDP_LEVEL);
28✔
6875
   vlog_set_ival(rsym, right);
28✔
6876

6877
   vlog_node_t v = vlog_new(V_UDP_EDGE);
28✔
6878
   vlog_set_subkind(v, V_UDP_SYMBOL_INPUT);
28✔
6879
   vlog_set_left(v, lsym);
28✔
6880
   vlog_set_right(v, rsym);
28✔
6881

6882
   vlog_set_loc(v, CURRENT_LOC);
28✔
6883
   return v;
28✔
6884
}
6885

6886
static void p_level_input_list(vlog_node_t entry)
63✔
6887
{
6888
   // level_symbol { level_symbol }
6889

6890
   BEGIN("level input list");
126✔
6891

6892
   do {
162✔
6893
      vlog_add_param(entry, p_level_symbol());
162✔
6894
   } while (not_at_token(tCOLON));
162✔
6895
}
63✔
6896

6897
static vlog_node_t p_edge_indicator(void)
101✔
6898
{
6899
   // ( level_symbol level_symbol ) | edge_symbol
6900

6901
   BEGIN("edge indicator");
202✔
6902

6903
   switch (peek()) {
101✔
6904
   case tUDPEDGE:
28✔
6905
      return p_edge_symbol();
28✔
6906
   case tLPAREN:
73✔
6907
      {
6908
         consume(tLPAREN);
73✔
6909

6910
         vlog_node_t v = vlog_new(V_UDP_EDGE);
73✔
6911
         vlog_set_left(v, p_level_symbol());
73✔
6912
         vlog_set_right(v, p_level_symbol());
73✔
6913

6914
         consume(tRPAREN);
73✔
6915

6916
         vlog_set_loc(v, CURRENT_LOC);
73✔
6917
         return v;
73✔
6918
      }
UNCOV
6919
      break;
×
UNCOV
6920
   default:
×
6921
      should_not_reach_here();
6922
   }
6923
}
6924

6925
static void p_seq_input_list(vlog_node_t entry)
101✔
6926
{
6927
   // level_input_list | edge_input_list
6928

6929
   BEGIN("sequential input list");
202✔
6930

6931
   bool have_edge = false;
101✔
6932
   do {
201✔
6933
      switch (peek()) {
201✔
6934
      case tUDPEDGE:
101✔
6935
      case tLPAREN:
6936
         vlog_add_param(entry, p_edge_indicator());
101✔
6937
         if (have_edge)
101✔
6938
            parse_error(&state.last_loc, "a sequential input list may have at "
1✔
6939
                        "most one edge indicator");
6940
         have_edge = true;
6941
         break;
6942

6943
      case tUDPLEVEL:
100✔
6944
         vlog_add_param(entry, p_level_symbol());
100✔
6945
         break;
100✔
6946

UNCOV
6947
      default:
×
UNCOV
6948
         one_of(tUDPEDGE, tUDPIND, tUDPLEVEL);
×
UNCOV
6949
         break;
×
6950
      }
6951
   } while (not_at_token(tCOLON));
201✔
6952
}
101✔
6953

6954
static vlog_node_t p_combinational_entry(void)
63✔
6955
{
6956
   // level_input_list : output_symbol ;
6957

6958
   BEGIN("combinational entry");
126✔
6959

6960
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
63✔
6961
   p_level_input_list(v);
63✔
6962

6963
   consume(tCOLON);
63✔
6964

6965
   vlog_add_param(v, p_output_symbol());
63✔
6966

6967
   consume(tSEMI);
63✔
6968

6969
   vlog_set_loc(v, CURRENT_LOC);
63✔
6970
   return v;
63✔
6971
}
6972

6973
static vlog_node_t p_combinational_body(void)
16✔
6974
{
6975
   // table combinational_entry { combinational_entry } endtable
6976

6977
   BEGIN("combinational UDP body");
32✔
6978

6979
   consume(tTABLE);
16✔
6980

6981
   scan_as_udp();
16✔
6982

6983
   vlog_node_t v = vlog_new(V_UDP_TABLE);
16✔
6984
   vlog_set_subkind(v, V_UDP_COMB);
16✔
6985
   vlog_set_ident(v, ident_new("combinational"));
16✔
6986

6987
   do {
63✔
6988
      vlog_add_param(v, p_combinational_entry());
63✔
6989
   } while (not_at_token(tENDTABLE));
63✔
6990

6991
   scan_as_verilog();
16✔
6992

6993
   consume(tENDTABLE);
16✔
6994

6995
   vlog_set_loc(v, CURRENT_LOC);
16✔
6996
   return v;
16✔
6997
}
6998

6999
static vlog_node_t p_sequential_entry(void)
101✔
7000
{
7001
   // seq_input_list : current_state : next_state ;
7002

7003
   BEGIN("sequential entry");
202✔
7004

7005
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
101✔
7006
   p_seq_input_list(v);
101✔
7007

7008
   consume(tCOLON);
101✔
7009

7010
   vlog_add_param(v, p_level_symbol());
101✔
7011

7012
   consume(tCOLON);
101✔
7013

7014
   vlog_add_param(v, p_next_state());
101✔
7015

7016
   consume(tSEMI);
101✔
7017

7018
   vlog_set_loc(v, CURRENT_LOC);
101✔
7019
   return v;
101✔
7020
}
7021

7022
static vlog_node_t p_udp_initial_statement(void)
6✔
7023
{
7024
   // initial output_port_identifier = init_val ;
7025

7026
   BEGIN("UDP initial statement");
12✔
7027

7028
   consume(tINITIAL);
6✔
7029

7030
   vlog_node_t ref = vlog_new(V_REF);
6✔
7031
   vlog_set_ident(ref, p_identifier());
6✔
7032
   vlog_set_loc(ref, &state.last_loc);
6✔
7033

7034
   vlog_symtab_lookup(symtab, ref);
6✔
7035

7036
   consume(tEQ);
6✔
7037

7038
   vlog_node_t v = vlog_new(V_BASSIGN);
6✔
7039
   vlog_set_target(v, ref);
6✔
7040
   vlog_set_value(v, p_integral_number());
6✔
7041

7042
   consume(tSEMI);
6✔
7043

7044
   vlog_set_loc(v, CURRENT_LOC);
6✔
7045
   return v;
6✔
7046
}
7047

7048
static vlog_node_t p_sequential_body(void)
15✔
7049
{
7050
   // [ udp_initial_statement ] table sequential_entry
7051
   //     { sequential_entry } endtable
7052

7053
   BEGIN("sequential UDP body");
30✔
7054

7055
   vlog_node_t v = vlog_new(V_UDP_TABLE);
15✔
7056
   vlog_set_subkind(v, V_UDP_SEQ);
15✔
7057
   vlog_set_ident(v, ident_new("sequential"));
15✔
7058

7059
   if (peek() == tINITIAL)
15✔
7060
      vlog_add_stmt(v, p_udp_initial_statement());
6✔
7061

7062
   consume(tTABLE);
15✔
7063

7064
   scan_as_udp();
15✔
7065

7066
   do {
101✔
7067
      vlog_add_param(v, p_sequential_entry());
101✔
7068
   } while (not_at_token(tENDTABLE));
101✔
7069

7070
   scan_as_verilog();
15✔
7071

7072
   consume(tENDTABLE);
15✔
7073

7074
   vlog_set_loc(v, CURRENT_LOC);
15✔
7075
   return v;
15✔
7076
}
7077

7078
static vlog_node_t p_udp_body(bool has_reg)
31✔
7079
{
7080
   // combinational_body | sequential_body
7081

7082
   BEGIN("UDP body");
62✔
7083

7084
   if (has_reg)
31✔
7085
      return p_sequential_body();
15✔
7086
   else
7087
      return p_combinational_body();
16✔
7088
}
7089

7090
static vlog_node_t p_udp_ansi_declaration(bool *has_reg)
5✔
7091
{
7092
   // { attribute_instance } primitive udp_identifier
7093
   //    ( udp_declaration_port_list ) ;
7094

7095
   BEGIN("UDP ANSI declaration");
10✔
7096

7097
   optional_attributes();
5✔
7098

7099
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
5✔
7100

7101
   consume(tPRIMITIVE);
5✔
7102

7103
   ident_t id, ext;
5✔
7104
   p_external_identifier(&id, &ext);
5✔
7105
   vlog_set_ident2(udp, id);
5✔
7106

7107
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
5✔
7108
   vlog_set_ident(udp, qual);
5✔
7109

7110
   vlog_symtab_push(symtab, udp);
5✔
7111

7112
   consume(tLPAREN);
5✔
7113

7114
   p_udp_declaration_port_list(udp, has_reg);
5✔
7115

7116
   consume(tRPAREN);
5✔
7117
   consume(tSEMI);
5✔
7118

7119
   vlog_set_loc(udp, CURRENT_LOC);
5✔
7120
   return udp;
5✔
7121
}
7122

7123
static vlog_node_t p_udp_declaration(void)
31✔
7124
{
7125
   // udp_nonansi_declaration udp_port_declaration { udp_port_declaration }
7126
   //        udp_body endprimitive [ : udp_identifier ]
7127
   //   | udp_ansi_declaration udp_body endprimitive [ : udp_identifier ]
7128
   //   | extern udp_nonansi_declaration
7129
   //   | extern udp_ansi_declaration
7130
   //   | { attribute_instance } primitive udp_identifier ( .* ) ;
7131
   //        { udp_port_declaration } udp_body endprimitive [ : udp_identifier ]
7132

7133
   BEGIN("UDP declaration");
62✔
7134

7135
   bool has_reg = false;
31✔
7136
   vlog_node_t udp;
31✔
7137
   if (peek_nth(4) == tID) {
31✔
7138
      udp = p_udp_nonansi_declaration();
26✔
7139

7140
      vlog_symtab_push(symtab, udp);
26✔
7141

7142
      do {
65✔
7143
         p_udp_port_declaration(udp, &has_reg);
65✔
7144
      } while (not_at_token(tTABLE, tINITIAL));
65✔
7145

7146
      const int nports = vlog_ports(udp);
26✔
7147
      for (int i = 0; i < nports; i++)
106✔
7148
         vlog_symtab_lookup(symtab, vlog_port(udp, i));
80✔
7149
   }
7150
   else
7151
      udp = p_udp_ansi_declaration(&has_reg);
5✔
7152

7153
   vlog_add_stmt(udp, p_udp_body(has_reg));
31✔
7154

7155
   vlog_symtab_pop(symtab);
31✔
7156

7157
   consume(tENDPRIMITIVE);
31✔
7158

7159
   return udp;
31✔
7160
}
7161

7162
static void p_package_item(vlog_node_t parent)
24✔
7163
{
7164
   // package_or_generate_item_declaration | anonymous_program
7165
   //   | package_export_declaration | timeunits_declaration
7166

7167
   BEGIN("package item");
48✔
7168

7169
   p_package_or_generate_item_declaration(parent);
24✔
7170
}
24✔
7171

7172
static vlog_node_t p_package_declaration(void)
5✔
7173
{
7174
   // { attribute_instance } package [ lifetime ] package_identifier ;
7175
   //    [ timeunits_declaration ] { { attribute_instance } package_item }
7176
   // endpackage [ : package_identifier ]
7177

7178
   BEGIN("package declaration");
10✔
7179

7180
   consume(tPACKAGE);
5✔
7181

7182
   param_kind = V_LOCALPARAM;
5✔
7183

7184
   if (scan(tSTATIC, tAUTOMATIC))
5✔
UNCOV
7185
      p_lifetime();
×
7186

7187
   vlog_node_t v = vlog_new(V_PACKAGE);
5✔
7188

7189
   ident_t id, ext;
5✔
7190
   p_external_identifier(&id, &ext);
5✔
7191
   vlog_set_ident2(v, id);
5✔
7192

7193
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
5✔
7194
   vlog_set_ident(v, qual);
5✔
7195

7196
   consume(tSEMI);
5✔
7197

7198
   vlog_symtab_push(symtab, v);
5✔
7199

7200
   while (not_at_token(tENDPACKAGE)) {
16✔
7201
      optional_attributes();
11✔
7202
      p_package_item(v);
11✔
7203
   }
7204

7205
   vlog_symtab_pop(symtab);
5✔
7206

7207
   consume(tENDPACKAGE);
5✔
7208

7209
   if (optional(tCOLON)) {
5✔
7210
      ident_t name = p_identifier();
2✔
7211
      if (id != name)
2✔
7212
         error_at(&state.last_loc, "'%s' does not match package name '%s'",
1✔
7213
                  istr(name), istr(id));
7214
   }
7215

7216
   vlog_set_loc(v, CURRENT_LOC);
5✔
7217
   return v;
5✔
7218
}
7219

7220
static vlog_node_t p_program_nonansi_header(void)
11✔
7221
{
7222
   // { attribute_instance } program [ lifetime ] program_identifier
7223
   //    { package_import_declaration } [ parameter_port_list ] list_of_ports ;
7224

7225
   BEGIN("program non-ANSI header");
22✔
7226

7227
   optional_attributes();
11✔
7228

7229
   vlog_node_t v = vlog_new(V_PROGRAM);
11✔
7230

7231
   consume(tPROGRAM);
11✔
7232

7233
   ident_t id, ext;
11✔
7234
   p_external_identifier(&id, &ext);
11✔
7235
   vlog_set_ident2(v, id);
11✔
7236

7237
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
11✔
7238
   vlog_set_ident(v, qual);
11✔
7239

7240
   consume(tSEMI);
11✔
7241

7242
   vlog_set_loc(v, CURRENT_LOC);
11✔
7243
   return v;
11✔
7244
}
7245

7246
static void p_non_port_program_item(vlog_node_t parent)
38✔
7247
{
7248
   // { attribute_instance } continuous_assign
7249
   //   | { attribute_instance } module_or_generate_item_declaration
7250
   //   | { attribute_instance } initial_construct
7251
   //   | { attribute_instance } final_construct
7252
   //   | { attribute_instance } concurrent_assertion_item
7253
   //   | timeunits_declaration
7254
   //   | program_generate_item
7255

7256
   BEGIN("non-port program item");
76✔
7257

7258
   optional_attributes();
38✔
7259

7260
   switch (peek()) {
38✔
7261
   case tINITIAL:
11✔
7262
      vlog_add_stmt(parent, p_initial_construct());
11✔
7263
      break;
11✔
7264
   default:
27✔
7265
      p_module_or_generate_item_declaration(parent);
27✔
7266
      break;
27✔
7267
   }
7268
}
38✔
7269

7270
static vlog_node_t p_program_declaration(void)
11✔
7271
{
7272
   // program_nonansi_header [ timeunits_declaration ] { program_item }
7273
   //       endprogram [ : program_identifier ]
7274
   //   | program_ansi_header [ timeunits_declaration ]
7275
   //       { non_port_program_item }
7276
   //   | { attribute_instance } program program_identifier ( .* ) ;
7277
   //       [ timeunits_declaration ] { program_item } endprogram
7278
   //       [ : program_identifier ]
7279
   //   | extern program_nonansi_header
7280
   //   | extern program_ansi_header
7281

7282
   BEGIN("program declaration");
22✔
7283

7284
   vlog_node_t v = p_program_nonansi_header();
11✔
7285

7286
   while (not_at_token(tENDPROGRAM))
49✔
7287
      p_non_port_program_item(v);
38✔
7288

7289
   consume(tENDPROGRAM);
11✔
7290

7291
   if (optional(tCOLON)) {
11✔
7292
      ident_t name = p_identifier();
1✔
7293
      if (name != vlog_ident2(v))
1✔
7294
         parse_error(&state.last_loc, "'%s' does not match program name '%s'",
1✔
7295
                     istr(name), istr(vlog_ident2(v)));
7296
   }
7297

7298
   vlog_set_loc(v, CURRENT_LOC);
11✔
7299
   return v;
11✔
7300
}
7301

7302
static vlog_node_t p_description(void)
1,064✔
7303
{
7304
   // module_declaration | udp_declaration | interface_declaration
7305
   //   | program_declaration | package_declaration
7306
   //   | { attribute_instance } package_item
7307
   //   | { attribute_instance } bind_directive
7308
   //   | config_declaration
7309

7310
   BEGIN("description");
2,128✔
7311

7312
   skip_over_attributes();
1,064✔
7313

7314
   switch (peek()) {
1,064✔
7315
   case tMODULE:
1,009✔
7316
      return p_module_declaration();
1,009✔
7317
   case tPRIMITIVE:
31✔
7318
      return p_udp_declaration();
31✔
7319
   case tPACKAGE:
5✔
7320
      return p_package_declaration();
5✔
7321
   case tPROGRAM:
11✔
7322
      return p_program_declaration();
11✔
7323
   case tCLASS:
8✔
7324
   case tTYPEDEF:
7325
   case tIMPORT:
7326
      {
7327
         vlog_node_t v = vlog_new(V_NAMESPACE);
8✔
7328

7329
         char hash[SHA_HEX_LEN];
8✔
7330
         get_hex_hash(loc_file_str(&state.last_loc), hash);
8✔
7331

7332
         ident_t name = ident_sprintf("%s$%d", hash, next_namespace++);
8✔
7333
         vlog_set_ident(v, ident_prefix(lib_name(lib_work()), name, '.'));
8✔
7334

7335
         do {
13✔
7336
            p_package_item(v);
13✔
7337
         } while (scan(tCLASS, tTYPEDEF, tIMPORT));
13✔
7338

7339
         vlog_set_loc(v, CURRENT_LOC);
8✔
7340
         return v;
8✔
7341
      }
7342
   default:
×
UNCOV
7343
      expect(tPRIMITIVE, tMODULE, tPACKAGE, tPROGRAM, tCLASS, tTYPEDEF,
×
7344
             tIMPORT);
UNCOV
7345
      return NULL;
×
7346
   }
7347
}
7348

7349
static void p_timescale_compiler_directive(void)
25✔
7350
{
7351
   // `timescale time_unit / time_precision
7352

7353
   BEGIN("timescale compiler directive");
50✔
7354

7355
   consume(tTIMESCALE);
25✔
7356

7357
   uint64_t unit_value = 1;
25✔
7358
   if (consume(tUNSNUM))
25✔
7359
      unit_value = atoll(state.last_lval.str);
24✔
7360

7361
   const char *unit_name = "fs";
25✔
7362
   if (consume(tID))
25✔
7363
      unit_name = istr(state.last_lval.ident);
25✔
7364

7365
   consume(tOVER);
25✔
7366

7367
   uint64_t prec_value = 1;
25✔
7368
   if (consume(tUNSNUM))
25✔
7369
      prec_value = atoll(state.last_lval.str);
24✔
7370

7371
   const char *prec_name = "fs";
25✔
7372
   if (consume(tID))
25✔
7373
      prec_name = istr(state.last_lval.ident);
24✔
7374

7375
   set_timescale(unit_value, unit_name, prec_value, prec_name, CURRENT_LOC);
25✔
7376
}
25✔
7377

7378
static void p_defaultnettype_compiler_directive(void)
12✔
7379
{
7380
   // `default_nettype wire | tri | tri0 | tri1 | wand | triand | wor
7381
   //    | trior | trireg | uwire | none
7382

7383
   BEGIN("default_nettype directive");
24✔
7384

7385
   consume(tDEFNETTYPE);
12✔
7386

7387
   switch (one_of(tWIRE, tTRI, tTRI0, tTRI1, tWAND, tTRIAND, tWOR, tTRIOR,
12✔
7388
                  tTRIREG, tUWIRE, tNONE)) {
7389
   case tWIRE: implicit_kind = V_NET_WIRE; break;
1✔
7390
   case tNONE: implicit_kind = V_NET_NONE; break;
1✔
7391
   }
7392
}
12✔
7393

7394
static void p_unconnected_drive_directive(void)
2✔
7395
{
7396
   // `unconnected_drive pull0 | pull1
7397

7398
   BEGIN("unconnected_drive directive");
4✔
7399

7400
   consume(tUNCTDRIVE);
2✔
7401

7402
   // TODO set default drive for unconnected nets
7403
   one_of(tPULL0, tPULL1);
2✔
7404
}
2✔
7405

7406
static void p_nounconnected_drive_directive(void)
1✔
7407
{
7408
   // `nounconnected_drive
7409

7410
   BEGIN("nounconnected_drive directive");
2✔
7411

7412
   consume(tNOUNCTDRIVE);
1✔
7413

7414
   // TODO reset default drive for unconnected nets
7415
}
1✔
7416

7417
static void p_keywords_directive(void)
12✔
7418
{
7419
   // `begin_keywords "version_specifier"
7420

7421
   BEGIN("keywords directive");
24✔
7422

7423
   consume(tBEGINKEYWORDS);
12✔
7424

7425
   if (consume(tSTRING)) {
12✔
7426
      vlog_version_t vers;
11✔
7427
      if (parse_verilog_version(tb_get(state.last_lval.text), &vers))
11✔
7428
         push_keywords(vers);
10✔
7429
      else
7430
         error_at(&state.last_loc, "\"%s\" is not a recognised Verilog or "
1✔
7431
                  "System Verilog version", tb_get(state.last_lval.text));
7432

7433
      tb_free(state.last_lval.text);
11✔
7434
   }
7435
}
12✔
7436

7437
static void p_endkeywords_directive(void)
11✔
7438
{
7439
   // `end_keywords
7440

7441
   BEGIN("endkeywords directive");
22✔
7442

7443
   consume(tENDKEYWORDS);
11✔
7444

7445
   if (!pop_keywords())
11✔
7446
      error_at(&state.last_loc, "`end_keywords directive without matching "
1✔
7447
               "`begin_keywords");
7448
}
11✔
7449

7450
static void p_resetall_directive(void)
1✔
7451
{
7452
   // `resetall
7453

7454
   BEGIN("resetall directive");
2✔
7455

7456
   consume(tRESETALL);
1✔
7457

7458
   implicit_kind = V_NET_WIRE;
1✔
7459
}
1✔
7460

7461
static void p_directive_list(void)
1,938✔
7462
{
7463
   BEGIN("directive list");
3,876✔
7464

7465
   for (;;) {
2,002✔
7466
      switch (peek()) {
2,002✔
7467
      case tDEFNETTYPE:
12✔
7468
         p_defaultnettype_compiler_directive();
12✔
7469
         break;
12✔
7470
      case tTIMESCALE:
25✔
7471
         p_timescale_compiler_directive();
25✔
7472
         break;
25✔
7473
      case tUNCTDRIVE:
2✔
7474
         p_unconnected_drive_directive();
2✔
7475
         break;
2✔
7476
      case tNOUNCTDRIVE:
1✔
7477
         p_nounconnected_drive_directive();
1✔
7478
         break;
1✔
7479
      case tBEGINKEYWORDS:
12✔
7480
         p_keywords_directive();
12✔
7481
         break;
12✔
7482
      case tENDKEYWORDS:
11✔
7483
         p_endkeywords_directive();
11✔
7484
         break;
11✔
7485
      case tRESETALL:
1✔
7486
         p_resetall_directive();
1✔
7487
         break;
1✔
7488
      default:
7489
         return;
1,938✔
7490
      }
7491
   }
7492
}
7493

7494
static vlog_node_t end_of_file(void)
874✔
7495
{
7496
   vlog_symtab_pop(symtab);
874✔
7497
   vlog_symtab_free(symtab);
874✔
7498
   symtab = NULL;
874✔
7499
   return NULL;
874✔
7500
}
7501

7502
static vlog_node_t p_source_text(void)
1,064✔
7503
{
7504
   // [ timeunits_declaration ] { description }
7505

7506
   BEGIN("source text");
2,128✔
7507

7508
   for (;;) {
1,064✔
7509
      if (peek() == tEOF) {
1,064✔
UNCOV
7510
         discard_global_arena();
×
UNCOV
7511
         return end_of_file();
×
7512
      }
7513

7514
      vlog_node_t v = p_description();
1,064✔
7515
      if (v == NULL || is_top_level(v))
1,064✔
7516
         return v;
1,064✔
7517
   }
7518
}
7519

7520
vlog_node_t vlog_parse(void)
1,938✔
7521
{
7522
   state.n_correct = RECOVER_THRESH;
1,938✔
7523
   param_kind = V_PARAM_DECL;
1,938✔
7524

7525
   for (int i = 0; i < ARRAY_LEN(atom_types); i++)
21,318✔
7526
      atom_types[i] = NULL;
19,380✔
7527

7528
   scan_as_verilog();
1,938✔
7529

7530
   if (symtab == NULL) {
1,938✔
7531
      symtab = vlog_symtab_new();
876✔
7532
      vlog_symtab_push(symtab, NULL);   // Compilation unit scope
876✔
7533
      vlog_symtab_poison(symtab, error_marker());
876✔
7534
   }
7535

7536
   p_directive_list();
1,938✔
7537

7538
   if (peek() == tEOF)
1,938✔
7539
      return end_of_file();
874✔
7540

7541
   make_new_arena();
1,064✔
7542

7543
   return p_source_text();
1,064✔
7544
}
7545

7546
void reset_verilog_parser(void)
1,716✔
7547
{
7548
   state.n_correct = RECOVER_THRESH;
1,716✔
7549
   state.tokenq_head = state.tokenq_tail = 0;
1,716✔
7550
   state.lex_fn = processed_yylex;
1,716✔
7551
   state.error_fn = vlog_parse_error_cb;
1,716✔
7552

7553
   implicit_kind = V_NET_WIRE;
1,716✔
7554
   last_attr = NULL;
1,716✔
7555
   next_namespace = 1;
1,716✔
7556

7557
   if (symtab != NULL) {
1,716✔
UNCOV
7558
      vlog_symtab_free(symtab);
×
UNCOV
7559
      symtab = NULL;
×
7560
   }
7561
}
1,716✔
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