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

nickg / nvc / 19747205009

27 Nov 2025 08:25AM UTC coverage: 92.555% (-0.01%) from 92.565%
19747205009

push

github

nickg
Handle unary operations on Verilog reals

22 of 27 new or added lines in 1 file covered. (81.48%)

226 existing lines in 4 files now uncovered.

75233 of 81285 relevant lines covered (92.55%)

454692.52 hits per line

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

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

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

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

34
#define RECOVER_THRESH 5
35
#define TRACE_PARSE    0
36
#define TRACE_RECOVERY 0
37
#define TOKENQ_SIZE    8
38

39
typedef struct {
40
   token_t  token;
41
   yylval_t lval;
42
   loc_t    loc;
43
} tokenq_t;
44

45
typedef struct {
46
   loc_t       start_loc;
47
   loc_t       last_loc;
48
   const char *hint_str;
49
   int         n_correct;
50
   tokenq_t    tokenq[TOKENQ_SIZE];
51
   int         tokenq_head;
52
   int         tokenq_tail;
53
   yylval_t    last_lval;
54
   token_t     opt_hist[8];
55
   int         nopt_hist;
56
#if TRACE_PARSE
57
   int         depth;
58
#endif
59
} parse_state_t;
60

61
typedef struct {
62
   const char *old_hint;
63
   loc_t       old_start_loc;
64
} rule_state_t;
65

66
static parse_state_t    state;
67
static vlog_kind_t      param_kind;
68
static vlog_net_kind_t  implicit_kind;
69
static vlog_symtab_t   *symtab;
70
static vlog_node_t      last_attr;
71

72
extern loc_t yylloc;
73

74
#define scan(...) _scan(1, __VA_ARGS__, -1)
75
#define expect(...) _expect(1, __VA_ARGS__, -1)
76
#define one_of(...) _one_of(1, __VA_ARGS__, -1)
77
#define not_at_token(...) ((peek() != tEOF) && !_scan(1, __VA_ARGS__, -1))
78
#define peek() peek_nth(1)
79

80
#define parse_error(loc, ...) do {              \
81
      if (state.n_correct >= RECOVER_THRESH)    \
82
         error_at((loc), __VA_ARGS__);          \
83
   } while (0)
84

85
#if TRACE_PARSE
86
static void _push_state(const rule_state_t *s);
87
#else
88
#define _push_state(s)
89
#endif
90

91
#define EXTEND(s)                                                      \
92
   __attribute__((cleanup(_pop_state), unused))                        \
93
   const rule_state_t _state = { state.hint_str, state.start_loc };    \
94
   state.hint_str = s;                                                 \
95
   _push_state(&_state);
96

97
#define BEGIN_WITH_HEAD(s, t)                            \
98
   EXTEND(s);                                            \
99
   state.start_loc = (t) ? *vlog_loc(t) : LOC_INVALID;   \
100

101
#define BEGIN(s)  BEGIN_WITH_HEAD(s, NULL)
102

103
#define CURRENT_LOC _diff_loc(&state.start_loc, &state.last_loc)
104

105
static vlog_node_t p_statement_or_null(void);
106
static vlog_node_t p_expression(void);
107
static vlog_node_t p_constant_expression(void);
108
static vlog_node_t p_data_type(void);
109
static void p_list_of_variable_decl_assignments(vlog_node_t parent,
110
                                                vlog_node_t datatype);
111
static vlog_node_t p_variable_lvalue(void);
112
static vlog_node_t p_select(ident_t id);
113
static vlog_net_kind_t p_net_type(void);
114
static void p_module_or_generate_item(vlog_node_t mod);
115
static void p_block_item_declaration(vlog_node_t parent);
116
static vlog_node_t p_attribute_instance(void);
117
static vlog_node_t  p_drive_strength(void);
118
static vlog_strength_t p_strength0(void);
119
static vlog_strength_t p_strength1(void);
120

121
static inline void _pop_state(const rule_state_t *r)
107,710✔
122
{
123
#if TRACE_PARSE
124
   printf("%*s<-- %s\n", state.depth--, "", state.hint_str);
125
#endif
126

127
   state.hint_str = r->old_hint;
107,710✔
128

129
   if (r->old_start_loc.first_line != LINE_INVALID)
107,710✔
130
      state.start_loc = r->old_start_loc;
36,534✔
131
}
107,710✔
132

133
#if TRACE_PARSE
134
static inline void _push_state(const rule_state_t *r)
135
{
136
   printf("%*s--> %s\n", state.depth++, "", state.hint_str);
137
}
138
#endif
139

140
static token_t peek_nth(int n)
226,815✔
141
{
142
   while (((state.tokenq_head - state.tokenq_tail) & (TOKENQ_SIZE - 1)) < n) {
274,227✔
143
      const token_t token = processed_yylex();
47,412✔
144

145
      int next = (state.tokenq_head + 1) & (TOKENQ_SIZE - 1);
47,412✔
146
      assert(next != state.tokenq_tail);
47,412✔
147

148
      extern yylval_t yylval;
47,412✔
149

150
      state.tokenq[state.tokenq_head].token = token;
47,412✔
151
      state.tokenq[state.tokenq_head].lval  = yylval;
47,412✔
152
      state.tokenq[state.tokenq_head].loc   = yylloc;
47,412✔
153

154
      state.tokenq_head = next;
47,412✔
155
   }
156

157
   const int pos = (state.tokenq_tail + n - 1) & (TOKENQ_SIZE - 1);
226,815✔
158
   return state.tokenq[pos].token;
226,815✔
159
}
160

161
static void drop_token(void)
47,072✔
162
{
163
   assert(state.tokenq_head != state.tokenq_tail);
47,072✔
164

165
   if (state.start_loc.first_line == LINE_INVALID)
47,072✔
166
      state.start_loc = state.tokenq[state.tokenq_tail].loc;
26,326✔
167

168
   state.last_lval = state.tokenq[state.tokenq_tail].lval;
47,072✔
169
   state.last_loc  = state.tokenq[state.tokenq_tail].loc;
47,072✔
170

171
   state.tokenq_tail = (state.tokenq_tail + 1) & (TOKENQ_SIZE - 1);
47,072✔
172

173
   state.nopt_hist = 0;
47,072✔
174
}
47,072✔
175

176
static void drop_tokens_until(token_t tok)
4✔
177
{
178
   token_t next = tEOF;
4✔
179
   do {
15✔
180
      free_token(tok, &state.last_lval);
15✔
181
      next = peek();
15✔
182
      drop_token();
15✔
183
   } while ((tok != next) && (next != tEOF));
15✔
184

185
#if TRACE_RECOVERY
186
   if (peek() != tEOF)
187
      fmt_loc(stdout, &(tokenq[tokenq_tail].loc));
188
#endif
189
}
4✔
190

191
static void _vexpect(va_list ap)
20✔
192
{
193
   if (state.n_correct >= RECOVER_THRESH) {
20✔
194
      diag_t *d = diag_new(DIAG_ERROR, &(state.tokenq[state.tokenq_tail].loc));
12✔
195
      diag_printf(d, "unexpected $yellow$%s$$ while parsing %s, expecting ",
12✔
196
                  token_str(peek()), state.hint_str);
197

198
      bool first = true;
12✔
199
      for (int i = 0; i < state.nopt_hist; i++) {
16✔
200
         diag_printf(d, "%s$yellow$%s$$", i == 0 ? "one of " : ", ",
5✔
201
                     token_str(state.opt_hist[i]));
202
         first = false;
4✔
203
      }
204

205
      int tok = va_arg(ap, int);
12✔
206
      while (tok != -1) {
101✔
207
         const int tmp = tok;
89✔
208
         tok = va_arg(ap, int);
89✔
209

210
         if (first && (tok != -1))
89✔
211
            diag_printf(d, "one of ");
4✔
212
         else if (!first)
85✔
213
            diag_printf(d, (tok == -1) ? " or " : ", ");
153✔
214

215
         diag_printf(d, "$yellow$%s$$", token_str(tmp));
89✔
216

217
         first = false;
89✔
218
      }
219

220
      diag_hint(d, &(state.tokenq[state.tokenq_tail].loc),
12✔
221
                "this token was unexpected");
222
      diag_emit(d);
12✔
223
   }
224

225
   state.n_correct = 0;
20✔
226

227
   drop_token();
20✔
228

229
   vlog_symtab_suppress(symtab);
20✔
230
}
20✔
231

232
static vlog_node_t peek_reference(void)
87✔
233
{
234
   assert(peek() == tID);
87✔
235
   ident_t id = state.tokenq[state.tokenq_tail].lval.ident;
87✔
236
   return vlog_symtab_query(symtab, id);
87✔
237
}
238

239
static void _expect(int dummy, ...)
12✔
240
{
241
   va_list ap;
12✔
242
   va_start(ap, dummy);
12✔
243
   _vexpect(ap);
12✔
244
   va_end(ap);
12✔
245
}
12✔
246

247
static bool consume(token_t tok)
47,049✔
248
{
249
   const token_t got = peek();
47,049✔
250
   if (tok != got) {
47,049✔
251
      expect(tok);
12✔
252
      return false;
12✔
253
   }
254
   else {
255
      state.n_correct++;
47,037✔
256
      drop_token();
47,037✔
257
      return true;
47,037✔
258
   }
259
}
260

261
static bool optional(token_t tok)
35,164✔
262
{
263
   if (peek() == tok) {
35,164✔
264
      consume(tok);
5,161✔
265
      return true;
5,161✔
266
   }
267
   else {
268
      if (state.nopt_hist < ARRAY_LEN(state.opt_hist))
30,003✔
269
         state.opt_hist[state.nopt_hist++] = tok;
30,003✔
270
      return false;
30,003✔
271
   }
272
}
273

274
static bool _scan(int dummy, ...)
14,799✔
275
{
276
   va_list ap;
14,799✔
277
   va_start(ap, dummy);
14,799✔
278

279
   token_t p = peek();
14,799✔
280
   bool found = false;
14,799✔
281

282
   while (!found) {
14,799✔
283
      const int tok = va_arg(ap, token_t);
49,736✔
284
      if (tok == -1)
49,736✔
285
         break;
286
      else if (p == tok)
37,002✔
287
         found = true;
288
   }
289

290
   va_end(ap);
14,799✔
291
   return found;
14,799✔
292
}
293

294
static int _one_of(int dummy, ...)
3,980✔
295
{
296
   va_list ap;
3,980✔
297
   va_start(ap, dummy);
3,980✔
298

299
   token_t p = peek();
3,980✔
300
   bool found = false;
3,980✔
301

302
   while (!found) {
3,980✔
303
      const int tok = va_arg(ap, token_t);
20,268✔
304
      if (tok == -1)
20,268✔
305
         break;
306
      else if (p == tok)
20,260✔
307
         found = true;
308
   }
309

310
   va_end(ap);
3,980✔
311

312
   if (found) {
3,980✔
313
      consume(p);
3,972✔
314
      return p;
3,972✔
315
   }
316
   else {
317
      va_start(ap, dummy);
8✔
318
      _vexpect(ap);
8✔
319
      va_end(ap);
8✔
320

321
      return -1;
8✔
322
   }
323
}
324

325
static const loc_t *_diff_loc(const loc_t *start, const loc_t *end)
35,611✔
326
{
327
   static loc_t result;
35,611✔
328

329
   result = get_loc(start->first_line,
35,611✔
330
                    start->first_column,
35,611✔
331
                    end->first_line + end->line_delta,
35,611✔
332
                    end->first_column + end->column_delta,
35,611✔
333
                    start->file_ref);
35,611✔
334
   return &result;
35,611✔
335
}
336

337
static void set_timescale(uint64_t unit_value, const char *unit_name,
13✔
338
                          uint64_t prec_value, const char *prec_name,
339
                          const loc_t *loc)
340
{
341
   // See IEEE 1800-2017 section 22.7 for rules
342

343
   struct {
13✔
344
      uint64_t    value;
345
      const char *name;
346
      uint64_t    parsed;
347
   } args[] = {
13✔
348
      { unit_value, unit_name },
349
      { prec_value, prec_name },
350
   };
351

352
   for (int i = 0; i < ARRAY_LEN(args); i++) {
39✔
353
      static const struct {
354
         const char *name;
355
         int64_t value;
356
      } valid_units[] = {
357
         { "s", INT64_C(60000000000000) },
358
         { "ms", 1000000000000 },
359
         { "us", 1000000000 },
360
         { "ns", 1000000 },
361
         { "ps", 1000 },
362
         { "fs", 1 },
363
      };
364

365
      bool name_valid = false;
132✔
366
      for (int j = 0; j < ARRAY_LEN(valid_units); j++) {
132✔
367
         if (strcmp(valid_units[j].name, args[i].name) == 0) {
131✔
368
            args[i].parsed = valid_units[j].value;
25✔
369
            name_valid = true;
25✔
370
            break;
25✔
371
         }
372
      }
373

374
      if (!name_valid)
25✔
375
         error_at(loc, "invalid time unit name '%s'", args[i].name);
1✔
376

377
      if (args[i].value != 1 && args[i].value != 10 && args[i].value != 100) {
26✔
378
         diag_t *d = diag_new(DIAG_ERROR, loc);
1✔
379
         diag_printf(d, "invalid order of magnitude in `timescale directive");
1✔
380
         diag_hint(d, NULL, "the valid values are 1, 10, and 100");
1✔
381
         diag_emit(d);
1✔
382
      }
383

384
      args[i].parsed *= args[i].value;
26✔
385
   }
386

387
   // TODO: do something with parsed scale/precision
388
}
13✔
389

390
static void skip_over_attributes(void)
3,433✔
391
{
392
   while (peek() == tATTRBEGIN)
3,451✔
393
      last_attr = p_attribute_instance();
18✔
394
}
3,433✔
395

396
static void optional_attributes(void)
10,410✔
397
{
398
   if (peek() == tATTRBEGIN) {
10,410✔
399
      // If the current token is (* and there is a saved attribute
400
      // instance from skip_over_attributes() then the attribute must
401
      // have been placed incorrectly as there were other tokens between
402
      // the last closing *) and this
403
      if (last_attr != NULL)
7✔
404
         parse_error(vlog_loc(last_attr), "attribute instance is not "
1✔
405
                     "allowed here");
406

407
      do {
7✔
408
         (void)p_attribute_instance();
7✔
409
      } while (peek() == tATTRBEGIN);
7✔
410
   }
411

412
   last_attr = NULL;
10,410✔
413
}
10,410✔
414

415
static ident_t error_marker(void)
342✔
416
{
417
   return well_known(W_ERROR);
342✔
418
}
419

420
static vlog_node_t dummy_expression(void)
×
421
{
422
   vlog_node_t v = vlog_new(V_NUMBER);
×
423
   vlog_set_number(v, number_from_bool(false));
×
424
   return v;
×
425
}
426

427
static vlog_node_t logic_type(void)
14✔
428
{
429
   vlog_node_t v = vlog_new(V_DATA_TYPE);
14✔
430
   vlog_set_subkind(v, DT_LOGIC);
14✔
431
   return v;
14✔
432
}
433

434
static vlog_node_t implicit_type(void)
58✔
435
{
436
   vlog_node_t v = vlog_new(V_DATA_TYPE);
58✔
437
   vlog_set_subkind(v, DT_IMPLICIT);
58✔
438
   return v;
58✔
439
}
440

441
static ident_t default_label(const char *prefix)
813✔
442
{
443
   return ident_sprintf("%s#%d#%d", prefix, state.last_loc.first_line,
1,626✔
444
                        state.last_loc.first_column);
813✔
445
}
446

447
static vlog_gate_kind_t get_gate_kind(token_t tok)
30✔
448
{
449
   switch (tok) {
30✔
450
   case tAND:      return V_GATE_AND;
451
   case tNAND:     return V_GATE_NAND;
3✔
452
   case tOR:       return V_GATE_OR;
8✔
453
   case tNOR:      return V_GATE_NOR;
×
454
   case tXOR:      return V_GATE_XOR;
3✔
455
   case tXNOR:     return V_GATE_XNOR;
×
456
   case tNOT:      return V_GATE_NOT;
3✔
457
   case tNOTIF0:   return V_GATE_NOTIF0;
×
458
   case tNOTIF1:   return V_GATE_NOTIF1;
×
459
   case tBUF:      return V_GATE_BUF;
5✔
460
   case tBUFIF0:   return V_GATE_BUFIF0;
1✔
461
   case tBUFIF1:   return V_GATE_BUFIF1;
×
462
   case tTRAN:     return V_GATE_TRAN;
1✔
UNCOV
463
   case tTRANIF0:  return V_GATE_TRANIF0;
×
464
   case tTRANIF1:  return V_GATE_TRANIF1;
1✔
UNCOV
465
   case tRTRAN:    return V_GATE_RTRAN;
×
UNCOV
466
   case tRTRANIF0: return V_GATE_RTRANIF0;
×
UNCOV
467
   case tRTRANIF1: return V_GATE_RTRANIF1;
×
468
   default:        should_not_reach_here();
469
   }
470
}
471

472
static void declare_port(vlog_node_t mod, vlog_node_t port)
216✔
473
{
474
   ident_t id = vlog_ident(port);
216✔
475

476
   const int nports = vlog_ports(mod);
216✔
477
   bool found = false;
216✔
478
   for (int i = 0; i < nports; i++) {
1,678✔
479
      vlog_node_t p = vlog_port(mod, i);
1,462✔
480
      if (vlog_ident(p) == id) {
1,462✔
481
         vlog_set_ref(p, port);
216✔
482
         found = true;
216✔
483
      }
484
   }
485

486
   if (!found) {
216✔
487
      diag_t *d = diag_new(DIAG_ERROR, vlog_loc(port));
2✔
488
      diag_printf(d, "'%s' does not appear in module port list", istr(id));
2✔
489
      diag_hint(d, vlog_loc(mod), "module declaration for '%s'",
2✔
490
                istr(vlog_ident2(mod)));
491
      diag_emit(d);
2✔
492
   }
493
}
216✔
494

495
static bool scan_block_item_declaration(void)
832✔
496
{
497
   return scan(tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM, tSVINT, tINTEGER,
832✔
498
               tSVREAL, tSHORTREAL, tREALTIME, tBIT, tLOGIC, tSHORTINT, tTIME);
499
}
500

501
static bool scan_tf_item_declaration(void)
75✔
502
{
503
   return scan(tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM, tSVINT, tINTEGER,
75✔
504
               tSVREAL, tSHORTREAL, tREALTIME, tBIT, tLOGIC, tSHORTINT, tTIME,
505
               tINPUT, tOUTPUT);
506
}
507

508
static ident_t p_identifier(void)
8,602✔
509
{
510
   if (consume(tID))
8,602✔
511
      return state.last_lval.ident;
8,601✔
512
   else
513
      return error_marker();
1✔
514
}
515

516
static void p_external_identifier(ident_t *id, ident_t *ext)
760✔
517
{
518
   if (consume(tID)) {
760✔
519
      *id = state.last_lval.ident;
760✔
520

521
      LOCAL_TEXT_BUF tb = tb_new();
760✔
522
      tb_istr(tb, state.last_lval.ident);
760✔
523
      tb_upcase(tb);
760✔
524

525
      *ext = ident_new(tb_get(tb));
760✔
526
   }
527
   else
UNCOV
528
      *id = *ext = error_marker();
×
529
}
760✔
530

531
static ident_t p_system_tf_identifier(void)
1,614✔
532
{
533
   if (consume(tSYSTASK))
1,614✔
534
      return state.last_lval.ident;
1,614✔
535
   else
UNCOV
536
      return error_marker();
×
537
}
538

539
static void p_attr_spec(void)
25✔
540
{
541
   // attr_name [ = constant_expression ]
542

543
   BEGIN("attribute specification");
50✔
544

545
   (void)p_identifier();
25✔
546

547
   if (optional(tEQ))
25✔
548
      (void)p_constant_expression();
1✔
549
}
25✔
550

551
static vlog_node_t p_attribute_instance(void)
25✔
552
{
553
   // (* attr_spec { , attr_spec } *)
554

555
   BEGIN("attribute instance");
25✔
556

557
   consume(tATTRBEGIN);
25✔
558

559
   vlog_node_t v = vlog_new(V_ATTR_INST);
25✔
560

561
   do {
25✔
562
      p_attr_spec();
25✔
563
   } while (optional(tCOMMA));
25✔
564

565
   consume(tATTREND);
25✔
566

567
   vlog_set_loc(v, CURRENT_LOC);
25✔
568
   return v;
25✔
569
}
570

571
static vlog_node_t p_unsigned_number(void)
4,217✔
572
{
573
   // decimal_digit { _ | decimal_digit }
574

575
   BEGIN("unsigned number");
4,217✔
576

577
   number_t n;
4,217✔
578
   if (consume(tUNSNUM)) {
4,217✔
579
      n = number_new(state.last_lval.str, CURRENT_LOC);
4,217✔
580
      free(state.last_lval.str);
4,217✔
581
   }
582
   else
UNCOV
583
      n = number_from_int(0);
×
584

585
   vlog_node_t v = vlog_new(V_NUMBER);
4,217✔
586
   vlog_set_number(v, n);
4,217✔
587
   vlog_set_loc(v, CURRENT_LOC);
4,217✔
588
   return v;
4,217✔
589
}
590

591
static vlog_node_t p_integral_number(void)
4,416✔
592
{
593
   // decimal_number | octal_number | binary_number | hex_number
594

595
   BEGIN("integral number");
8,832✔
596

597
   if (peek() == tUNSNUM)
4,416✔
598
      return p_unsigned_number();
3,552✔
599
   else {
600
      number_t n;
864✔
601
      if (consume(tNUMBER)) {
864✔
602
         n = number_new(state.last_lval.str, &state.last_loc);
863✔
603
         free(state.last_lval.str);
863✔
604
      }
605
      else
606
         n = number_from_int(0);
1✔
607

608
      vlog_node_t v = vlog_new(V_NUMBER);
864✔
609
      vlog_set_number(v, n);
864✔
610
      vlog_set_loc(v, CURRENT_LOC);
864✔
611
      return v;
864✔
612
   }
613
}
614

615
static vlog_node_t p_real_number(void)
46✔
616
{
617
   // fixed_point_number
618
   //   | unsigned_number [ . unsigned_number ] exp [ sign ] unsigned_number
619

620
   BEGIN("real number");
46✔
621

622
   consume(tREAL);
46✔
623

624
   vlog_node_t v = vlog_new(V_REAL);
46✔
625
   vlog_set_dval(v, state.last_lval.real);
46✔
626
   vlog_set_loc(v, CURRENT_LOC);
46✔
627
   return v;
46✔
628
}
629

630
static vlog_node_t p_number(void)
4,453✔
631
{
632
   // integral_number | real_number
633

634
   BEGIN("number");
8,906✔
635

636
   if (peek() == tREAL)
4,453✔
637
      return p_real_number();
42✔
638
   else
639
      return p_integral_number();
4,411✔
640
}
641

642
static vlog_node_t p_string_literal(void)
1,126✔
643
{
644
   // " { Any_ASCII_Characters } "
645

646
   BEGIN("string literal");
1,126✔
647

648
   number_t n;
1,126✔
649
   if (consume(tSTRING)) {
1,126✔
650
      text_buf_t *tb = state.last_lval.text;
1,126✔
651
      n = number_from_string(tb_get(tb), tb_len(tb));
1,126✔
652
      tb_free(tb);
1,126✔
653
   }
654
   else
655
      should_not_reach_here();
656

657
   vlog_node_t v = vlog_new(V_STRING);
1,126✔
658
   vlog_set_number(v, n);
1,126✔
659
   vlog_set_loc(v, CURRENT_LOC);
1,126✔
660
   return v;
2,252✔
661
}
662

663
static vlog_node_t p_primary_literal(void)
5,579✔
664
{
665
   // number | time_literal | unbased_unsized_literal | string_literal
666

667
   BEGIN("primary literal");
11,158✔
668

669
   switch (peek()) {
5,579✔
670
   case tNUMBER:
4,453✔
671
   case tUNSNUM:
672
   case tREAL:
673
      return p_number();
4,453✔
674
   case tSTRING:
1,126✔
675
      return p_string_literal();
1,126✔
UNCOV
676
   default:
×
UNCOV
677
      one_of(tNUMBER, tUNSNUM, tREAL, tSTRING);
×
UNCOV
678
      return dummy_expression();
×
679
   }
680
}
681

682
static vlog_node_t p_constant_select(ident_t id)
303✔
683
{
684
   // [ { . member_identifier constant_bit_select } . member_identifier ]
685
   //    constant_bit_select [ [ constant_part_select_range ] ]
686

687
   EXTEND("constant select");
606✔
688

689
   // Checked for constant-ness later
690
   return p_select(id);
303✔
691
}
692

693
static vlog_node_t p_constant_expression(void)
1,361✔
694
{
695
   // constant_primary | unary_operator { attribute_instance } constant_primary
696
   //   | constant_expression binary_operator { attribute_instance }
697
   //       constant_expression
698
   //   | constant_expression ? { attribute_instance }
699
   //       constant_expression : constant_expression
700

701
   BEGIN("constant expression");
2,722✔
702

703
   // Checked for constant-ness later
704
   return p_expression();
1,361✔
705
}
706

707
static void p_constant_range(vlog_node_t *left, vlog_node_t *right)
546✔
708
{
709
   // constant_expression : constant_expression
710

711
   BEGIN("constant range");
546✔
712

713
   *left = p_constant_expression();
546✔
714

715
   consume(tCOLON);
546✔
716

717
   *right = p_constant_expression();
546✔
718
}
546✔
719

720
static vlog_node_t p_constant_range_expression(void)
2✔
721
{
722
   // constant_expression | constant_part_select_range
723

724
   BEGIN("constant range expression");
4✔
725

726
   return p_constant_expression();
2✔
727
}
728

729
static vlog_node_t p_constant_mintypmax_expression(void)
5✔
730
{
731
   // constant_expression
732
   //   | constant_expression : constant_expression : constant_expression
733

734
   return p_constant_expression();
5✔
735
}
736

737
static vlog_node_t p_packed_dimension(void)
520✔
738
{
739
   // [ constant_range ] | unsized_dimension
740

741
   BEGIN("packed dimension");
520✔
742

743
   consume(tLSQUARE);
520✔
744

745
   vlog_node_t left, right;
520✔
746
   p_constant_range(&left, &right);
520✔
747

748
   consume(tRSQUARE);
520✔
749

750
   vlog_node_t v = vlog_new(V_DIMENSION);
520✔
751
   vlog_set_subkind(v, V_DIM_PACKED);
520✔
752
   vlog_set_left(v, left);
520✔
753
   vlog_set_right(v, right);
520✔
754
   vlog_set_loc(v, CURRENT_LOC);
520✔
755

756
   return v;
520✔
757
}
758

759
static vlog_node_t p_unpacked_dimension(void)
26✔
760
{
761
   // [ constant_range ] | [ constant_expression ]
762

763
   BEGIN("unpacked dimension");
26✔
764

765
   consume(tLSQUARE);
26✔
766

767
   vlog_node_t left, right;
26✔
768
   p_constant_range(&left, &right);
26✔
769

770
   consume(tRSQUARE);
26✔
771

772
   vlog_node_t v = vlog_new(V_DIMENSION);
26✔
773
   vlog_set_subkind(v, V_DIM_UNPACKED);
26✔
774
   vlog_set_left(v, left);
26✔
775
   vlog_set_right(v, right);
26✔
776
   vlog_set_loc(v, CURRENT_LOC);
26✔
777

778
   return v;
26✔
779
}
780

781
static vlog_node_t p_data_type_or_void(void)
21✔
782
{
783
   // data_type | void
784

785
   BEGIN("data type or void");
42✔
786

787
   if (optional(tVOID))
21✔
788
      return NULL;
789
   else
790
      return p_data_type();
20✔
791
}
792

793
static void p_struct_union_member(vlog_node_t v)
12✔
794
{
795
   // { attribute_instance } [ random_qualifier ] data_type_or_void
796
   //    list_of_variable_decl_assignments ;
797

798
   BEGIN("struct or union member");
24✔
799

800
   optional_attributes();
12✔
801

802
   vlog_node_t dt = p_data_type_or_void();
12✔
803
   p_list_of_variable_decl_assignments(v, dt);
12✔
804

805
   consume(tSEMI);
12✔
806
}
12✔
807

808
static void p_enum_name_declaration(vlog_node_t parent)
50✔
809
{
810
   // enum_identifier [ [ integral_number [ : integral_number ] ] ]
811
   //   [ = constant_expression ]
812

813
   BEGIN("enum name declaration");
100✔
814

815
   vlog_node_t v = vlog_new(V_ENUM_NAME);
50✔
816
   vlog_set_ident(v, p_identifier());
50✔
817
   vlog_set_type(v, parent);
50✔
818

819
   if (optional(tEQ))
50✔
820
      vlog_set_value(v, p_constant_expression());
17✔
821

822
   vlog_add_decl(parent, v);
50✔
823

824
   vlog_set_loc(v, CURRENT_LOC);
50✔
825
   vlog_symtab_put(symtab, v);
50✔
826
}
50✔
827

828
static vlog_node_t p_integer_atom_type(void)
118✔
829
{
830
   // byte | shortint | int | longint | integer | time
831

832
   BEGIN("integer atom type");
118✔
833

834
   data_type_t dt = DT_BYTE;
118✔
835
   switch (one_of(tBYTE, tSHORTINT, tSVINT, tLONGINT, tINTEGER, tTIME)) {
118✔
836
   case tBYTE:     dt = DT_BYTE; break;
837
   case tSHORTINT: dt = DT_SHORTINT; break;
838
   case tSVINT:    dt = DT_INT; break;
839
   case tLONGINT:  dt = DT_LONGINT; break;
840
   case tINTEGER:  dt = DT_INTEGER; break;
841
   case tTIME:     dt = DT_TIME; break;
842
   }
843

844
   vlog_node_t v = vlog_new(V_DATA_TYPE);
118✔
845
   vlog_set_subkind(v, dt);
118✔
846
   vlog_set_loc(v, &state.last_loc);
118✔
847
   return v;
118✔
848
}
849

850
static vlog_node_t p_integer_vector_type(void)
510✔
851
{
852
   //  bit | logic | reg
853

854
   BEGIN("integer vector type");
510✔
855

856
   data_type_t dt = DT_LOGIC;
510✔
857
   switch (one_of(tBIT, tLOGIC, tREG)) {
510✔
858
   case tBIT:    dt = DT_BIT; break;
12✔
859
   case tLOGIC:
860
   case tREG:    dt = DT_LOGIC; break;
861
   }
862

863
   vlog_node_t v = vlog_new(V_DATA_TYPE);
510✔
864
   vlog_set_subkind(v, dt);
510✔
865
   vlog_set_loc(v, &state.last_loc);
510✔
866
   return v;
510✔
867
}
868

869
static vlog_node_t p_non_integer_type(void)
15✔
870
{
871
   // shortreal | real | realtime
872

873
   BEGIN("non-integer type");
15✔
874

875
   data_type_t dt = DT_REAL;
15✔
876
   switch (one_of(tSVREAL, tSHORTREAL, tREALTIME)) {
15✔
877
   case tSVREAL:    dt = DT_REAL; break;
878
   case tSHORTREAL: dt = DT_SHORTREAL; break;
2✔
879
   case tREALTIME:  dt = DT_REALTIME; break;
1✔
880
   }
881

882
   vlog_node_t v = vlog_new(V_DATA_TYPE);
15✔
883
   vlog_set_subkind(v, dt);
15✔
884
   vlog_set_loc(v, &state.last_loc);
15✔
885
   return v;
15✔
886
}
887

888
static vlog_node_t p_struct_union(void)
7✔
889
{
890
   // struct | union [ tagged ]
891

892
   BEGIN("struct or union");
14✔
893

894
   switch (one_of(tSTRUCT, tUNION)) {
7✔
895
   case tUNION:
2✔
896
      {
897
         vlog_node_t v = vlog_new(V_UNION_DECL);
2✔
898
         optional(tTAGGED);
2✔
899
         return v;
2✔
900
      }
901
   case tSTRUCT:
5✔
902
   default:
903
      return vlog_new(V_STRUCT_DECL);
5✔
904
   }
905
}
906

907
static vlog_flags_t p_signing(void)
15✔
908
{
909
   // signed | unsigned
910

911
   BEGIN("signing");
30✔
912

913
   switch (one_of(tSIGNED, tUNSIGNED)) {
15✔
914
   case tSIGNED: return VLOG_F_SIGNED;
915
   default: return 0;
1✔
916
   }
917
}
918

919
static vlog_node_t p_enum_base_type(void)
12✔
920
{
921
   // integer_atom_type [ signing ]
922
   //   | integer_vector_type [ signing ] [ packed_dimension ]
923
   //   | type_identifier [ packed_dimension ]
924

925
   BEGIN("enum base type");
24✔
926

927
   switch (peek()) {
12✔
928
   case tBYTE:
10✔
929
   case tSHORTINT:
930
   case tSVINT:
931
   case tLONGINT:
932
   case tINTEGER:
933
   case tTIME:
934
      {
935
         vlog_node_t v = p_integer_atom_type();
10✔
936

937
         if (scan(tSIGNED, tUNSIGNED))
10✔
UNCOV
938
            vlog_set_flags(v, p_signing());
×
939

940
         return v;
941
      }
942

943
   case tBIT:
2✔
944
   case tLOGIC:
945
   case tREG:
946
      {
947
         vlog_node_t v = p_integer_vector_type();
2✔
948

949
         if (scan(tSIGNED, tUNSIGNED))
2✔
UNCOV
950
            vlog_set_flags(v, p_signing());
×
951

952
         if (scan(tLSQUARE))
2✔
953
            p_packed_dimension();
2✔
954

955
         return v;
956
      }
957

UNCOV
958
   default:
×
UNCOV
959
      p_identifier();
×
960

UNCOV
961
      if (scan(tLSQUARE))
×
UNCOV
962
         p_packed_dimension();
×
963

964
      return NULL;
965
   }
966
}
967

968
static vlog_node_t p_data_type(void)
681✔
969
{
970
   // integer_vector_type [ signing ] { packed_dimension }
971
   //   | integer_atom_type [ signing ] | non_integer_type
972
   //   | struct_union [ packed [ signing ] ]
973
   //       { struct_union_member { struct_union_member } } { packed_dimension }
974
   //   | enum [ enum_base_type ] { enum_name_declaration
975
   //       { , enum_name_declaration } } { packed_dimension }
976
   //   | string | chandle
977
   //   | virtual [ interface ] interface_identifier
978
   //       [ parameter_value_assignment ] [ . modport_identifier ]
979
   //   | [ class_scope | package_scope ] type_identifier { packed_dimension }
980
   //   | class_type | event | ps_covergroup_identifier | type_reference
981

982
   BEGIN("data type");
1,362✔
983

984
   switch (peek()) {
681✔
985
   case tBIT:
508✔
986
   case tLOGIC:
987
   case tREG:
988
      {
989
         vlog_node_t v = p_integer_vector_type();
508✔
990

991
         if (scan(tSIGNED, tUNSIGNED))
508✔
992
            vlog_set_flags(v, p_signing());
13✔
993

994
         while (peek() == tLSQUARE)
775✔
995
            vlog_add_range(v, p_packed_dimension());
267✔
996

997
         return v;
998
      }
999

1000
   case tBYTE:
108✔
1001
   case tSHORTINT:
1002
   case tSVINT:
1003
   case tLONGINT:
1004
   case tINTEGER:
1005
   case tTIME:
1006
      {
1007
         vlog_node_t v = p_integer_atom_type();
108✔
1008

1009
         if (scan(tSIGNED, tUNSIGNED))
108✔
1010
            vlog_set_flags(v, p_signing());
1✔
1011

1012
         return v;
1013
      }
1014

1015
   case tSVREAL:
15✔
1016
   case tREALTIME:
1017
   case tSHORTREAL:
1018
      return p_non_integer_type();
15✔
1019

1020
   case tSTRUCT:
7✔
1021
   case tUNION:
1022
      {
1023
         vlog_node_t v = p_struct_union();
7✔
1024

1025
         (void)optional(tPACKED);
7✔
1026

1027
         consume(tLBRACE);
7✔
1028

1029
         vlog_symtab_push(symtab, v);
7✔
1030

1031
         do {
12✔
1032
            p_struct_union_member(v);
12✔
1033
         } while (not_at_token(tRBRACE));
12✔
1034

1035
         vlog_symtab_pop(symtab);
7✔
1036

1037
         consume(tRBRACE);
7✔
1038

1039
         if (peek() == tLSQUARE)
7✔
UNCOV
1040
            vlog_add_range(v, p_packed_dimension());
×
1041

1042
         vlog_set_loc(v, CURRENT_LOC);
7✔
1043
         return v;
7✔
1044
      }
1045

1046
   case tENUM:
20✔
1047
      {
1048
         consume(tENUM);
20✔
1049

1050
         vlog_node_t v = vlog_new(V_ENUM_DECL);
20✔
1051

1052
         if (peek() != tLBRACE)
20✔
1053
            vlog_set_type(v, p_enum_base_type());
12✔
1054

1055
         consume(tLBRACE);
20✔
1056

1057
         do {
50✔
1058
            p_enum_name_declaration(v);
50✔
1059
         } while (optional(tCOMMA));
50✔
1060

1061
         consume(tRBRACE);
20✔
1062

1063
         while (peek() == tLSQUARE)
22✔
1064
            vlog_add_range(v, p_packed_dimension());
2✔
1065

1066
         vlog_set_loc(v, CURRENT_LOC);
20✔
1067
         return v;
20✔
1068
      }
1069

1070
   case tEVENT:
1✔
1071
      {
1072
         consume(tEVENT);
1✔
1073

1074
         vlog_node_t v = vlog_new(V_DATA_TYPE);
1✔
1075
         vlog_set_subkind(v, DT_EVENT);
1✔
1076
         vlog_set_loc(v, &state.last_loc);
1✔
1077

1078
         return v;
1✔
1079
      }
1080

1081
   case tID:
18✔
1082
      {
1083
         ident_t id = p_identifier();
18✔
1084
         vlog_node_t dt = vlog_symtab_query(symtab, id);
18✔
1085
         if (dt == NULL) {
18✔
1086
            error_at(&state.last_loc, "no data type declaration for '%s'",
1✔
1087
                     istr(id));
1088
            return logic_type();
1✔
1089
         }
1090
         else if (!is_data_type(dt)) {
17✔
1091
            diag_t *d = diag_new(DIAG_ERROR, &state.last_loc);
1✔
1092
            diag_printf(d, "'%s' is not a data type", istr(id));
1✔
1093
            diag_hint(d, vlog_loc(dt), "'%s' declared here", istr(id));
1✔
1094
            diag_emit(d);
1✔
1095

1096
            return logic_type();
1✔
1097
         }
1098
         else
1099
            return dt;
1100
      }
1101

1102
   case tSTRINGK:
4✔
1103
      {
1104
         consume(tSTRINGK);
4✔
1105

1106
         vlog_node_t v = vlog_new(V_DATA_TYPE);
4✔
1107
         vlog_set_subkind(v, DT_STRING);
4✔
1108
         vlog_set_loc(v, &state.last_loc);
4✔
1109

1110
         return v;
4✔
1111
      }
1112

UNCOV
1113
   default:
×
UNCOV
1114
      one_of(tBIT, tLOGIC, tREG, tBYTE, tSHORTINT, tSVINT, tLONGINT, tINTEGER,
×
1115
             tTIME, tSVREAL, tREALTIME, tSHORTREAL, tSTRUCT, tUNION, tENUM,
1116
             tEVENT, tID, tSTRINGK);
UNCOV
1117
      return logic_type();
×
1118
   }
1119
}
1120

1121
static vlog_node_t p_implicit_data_type(void)
624✔
1122
{
1123
   // [ signing ] { packed_dimension }
1124

1125
   BEGIN("implicit data type");
624✔
1126

1127
   vlog_node_t v = vlog_new(V_DATA_TYPE);
624✔
1128
   vlog_set_subkind(v, DT_IMPLICIT);
624✔
1129

1130
   if (scan(tSIGNED, tUNSIGNED))
624✔
1131
      vlog_set_flags(v, p_signing());
1✔
1132

1133
   while (peek() == tLSQUARE)
872✔
1134
      vlog_add_range(v, p_packed_dimension());
248✔
1135

1136
   vlog_set_loc(v, CURRENT_LOC);
624✔
1137
   return v;
624✔
1138
}
1139

1140
static vlog_node_t p_data_type_or_implicit(void)
1,229✔
1141
{
1142
   // data_type | implicit_data_type
1143

1144
   BEGIN("data type or implicit");
2,458✔
1145

1146
   switch (peek()) {
1,229✔
1147
   case tID:
381✔
1148
      if (peek_nth(2) == tID)
381✔
1149
         return p_data_type();
18✔
1150
      else
1151
         return p_implicit_data_type();
363✔
1152
      break;
616✔
1153
   case tREG:
616✔
1154
   case tSTRUCT:
1155
   case tUNION:
1156
   case tENUM:
1157
   case tSVINT:
1158
   case tINTEGER:
1159
   case tSVREAL:
1160
   case tSHORTREAL:
1161
   case tREALTIME:
1162
   case tTIME:
1163
   case tLOGIC:
1164
   case tBIT:
1165
   case tSHORTINT:
1166
   case tLONGINT:
1167
   case tBYTE:
1168
   case tEVENT:
1169
   case tSTRINGK:
1170
      return p_data_type();
616✔
1171
   default:
232✔
1172
      return p_implicit_data_type();
232✔
1173
   }
1174
}
1175

1176
static void p_net_port_type(vlog_net_kind_t *kind, vlog_node_t *dt)
225✔
1177
{
1178
   // [ net_type ] data_type_or_implicit | net_type_identifier
1179
   //   | interconnect implicit_data_type
1180

1181
   BEGIN("net port type");
225✔
1182

1183
   if (scan(tSUPPLY0, tSUPPLY1, tTRI, tTRIAND, tTRIOR, tTRIREG,
225✔
1184
            tTRI0, tTRI1, tUWIRE, tWIRE, tWAND, tWOR))
1185
      *kind = p_net_type();
53✔
1186
   else
1187
      *kind = V_NET_WIRE;
172✔
1188

1189
   *dt = p_data_type_or_implicit();
225✔
1190
}
225✔
1191

1192
static vlog_node_t p_var_data_type(void)
13✔
1193
{
1194
   // data_type | var data_type_or_implicit
1195

1196
   BEGIN("var data type");
26✔
1197

1198
   return p_data_type();
13✔
1199
}
1200

1201
static vlog_node_t p_variable_port_type(void)
13✔
1202
{
1203
   // var_data_type
1204

1205
   BEGIN("variable port type");
26✔
1206

1207
   return p_var_data_type();
13✔
1208
}
1209

1210
static void p_list_of_port_identifiers(vlog_node_t mod, v_port_kind_t kind,
178✔
1211
                                       vlog_node_t datatype)
1212
{
1213
   // port_identifier { unpacked_dimension }
1214
   //    { , port_identifier { unpacked_dimension } }
1215

1216
   BEGIN("list of port identifiers");
356✔
1217

1218
   do {
203✔
1219
      ident_t id, ext;
203✔
1220
      p_external_identifier(&id, &ext);
203✔
1221

1222
      vlog_node_t v = vlog_new(V_PORT_DECL);
203✔
1223
      vlog_set_subkind(v, kind);
203✔
1224
      vlog_set_ident(v, id);
203✔
1225
      vlog_set_ident2(v, ext);
203✔
1226
      vlog_set_type(v, datatype);
203✔
1227
      vlog_set_loc(v, &state.last_loc);
203✔
1228

1229
      vlog_add_decl(mod, v);
203✔
1230
      vlog_symtab_put(symtab, v);
203✔
1231

1232
      declare_port(mod, v);
203✔
1233
   } while (optional(tCOMMA));
203✔
1234
}
178✔
1235

1236
static void p_list_of_variable_port_identifiers(vlog_node_t mod,
13✔
1237
                                                v_port_kind_t kind,
1238
                                                vlog_node_t datatype)
1239
{
1240
   // port_identifier { variable_dimension } [ = constant_expression ]
1241
   //   { , port_identifier { variable_dimension } [ = constant_expression ] }
1242

1243
   BEGIN("list of variable port identifiers");
26✔
1244

1245
   do {
13✔
1246
      ident_t id, ext;
13✔
1247
      p_external_identifier(&id, &ext);
13✔
1248

1249
      vlog_node_t v = vlog_new(V_PORT_DECL);
13✔
1250
      vlog_set_subkind(v, kind);
13✔
1251
      vlog_set_ident(v, id);
13✔
1252
      vlog_set_ident2(v, ext);
13✔
1253
      vlog_set_type(v, datatype);
13✔
1254
      vlog_set_loc(v, &state.last_loc);
13✔
1255

1256
      vlog_add_decl(mod, v);
13✔
1257
      vlog_symtab_put(symtab, v);
13✔
1258

1259
      declare_port(mod, v);
13✔
1260
   } while (optional(tCOMMA));
13✔
1261
}
13✔
1262

1263
static void p_inout_declaration(vlog_node_t mod)
1✔
1264
{
1265
   // inout net_port_type list_of_port_identifiers
1266

1267
   BEGIN("inout declaration");
2✔
1268

1269
   consume(tINOUT);
1✔
1270

1271
   vlog_node_t dt;
1✔
1272
   vlog_net_kind_t kind;
1✔
1273
   p_net_port_type(&kind, &dt);
1✔
1274

1275
   p_list_of_port_identifiers(mod, V_PORT_INOUT, dt);
1✔
1276
}
1✔
1277

1278
static void p_input_declaration(vlog_node_t mod)
114✔
1279
{
1280
   // input net_port_type list_of_port_identifiers
1281
   //   | input variable_port_type list_of_variable_identifiers
1282

1283
   BEGIN("input declaration");
228✔
1284

1285
   consume(tINPUT);
114✔
1286

1287
   vlog_node_t dt;
114✔
1288
   vlog_net_kind_t kind;
114✔
1289
   switch (peek()) {
114✔
UNCOV
1290
   case tREG:
×
UNCOV
1291
      dt = p_variable_port_type();
×
UNCOV
1292
      p_list_of_variable_port_identifiers(mod, V_PORT_INPUT, dt);
×
UNCOV
1293
      break;
×
1294
   default:
114✔
1295
      p_net_port_type(&kind, &dt);
114✔
1296
      p_list_of_port_identifiers(mod, V_PORT_INPUT, dt);
114✔
1297
      break;
114✔
1298
   }
1299
}
114✔
1300

1301
static void p_output_declaration(vlog_node_t mod)
76✔
1302
{
1303
   // output net_port_type list_of_port_identifiers
1304
   //   | output variable_port_type list_of_variable_port_identifiers
1305

1306
   BEGIN("output declaration");
152✔
1307

1308
   consume(tOUTPUT);
76✔
1309

1310
   switch (peek()) {
76✔
1311
   case tREG:
13✔
1312
      {
1313
         vlog_node_t dt = p_variable_port_type();
13✔
1314
         p_list_of_variable_port_identifiers(mod, V_PORT_OUTPUT, dt);
13✔
1315
      }
1316
      break;
13✔
1317
   default:
63✔
1318
      {
1319
         vlog_node_t dt;
63✔
1320
         vlog_net_kind_t kind;
63✔
1321
         p_net_port_type(&kind, &dt);
63✔
1322
         p_list_of_port_identifiers(mod, V_PORT_OUTPUT, dt);
63✔
1323
      }
1324
      break;
63✔
1325
   }
1326
}
76✔
1327

1328
static void p_port_declaration(vlog_node_t mod)
191✔
1329
{
1330
   // { attribute_instance } inout_declaration
1331
   //   | { attribute_instance } input_declaration
1332
   //   | { attribute_instance } output_declaration
1333
   //   | { attribute_instance } ref_declaration
1334
   //   | { attribute_instance } interface_port_declaration
1335

1336
   BEGIN("port declaration");
382✔
1337

1338
   switch (peek()) {
191✔
1339
   case tINOUT: p_inout_declaration(mod); break;
1✔
1340
   case tINPUT: p_input_declaration(mod); break;
114✔
1341
   case tOUTPUT: p_output_declaration(mod); break;
76✔
1342
   default: should_not_reach_here();
1343
   }
1344
}
191✔
1345

1346
static void p_net_port_header(v_port_kind_t *dir, vlog_node_t *dt)
47✔
1347
{
1348
   // [ port_direction ] net_port_type
1349

1350
   BEGIN("net port header");
94✔
1351

1352
   if (optional(tINPUT))
47✔
1353
      *dir = V_PORT_INPUT;
26✔
1354
   else if (optional(tINOUT))
21✔
UNCOV
1355
      *dir = V_PORT_INOUT;
×
1356
   else if (optional(tOUTPUT))
21✔
1357
      *dir = V_PORT_OUTPUT;
21✔
1358

1359
   vlog_net_kind_t kind;
47✔
1360
   p_net_port_type(&kind, dt);
47✔
1361
}
47✔
1362

1363
static void p_part_select_range(vlog_node_t ps)
162✔
1364
{
1365
   // constant_expression : constant_expression
1366
   //   | expression +: constant_expression
1367
   //   | expression -: constant_expression
1368

1369
   BEGIN("part select range");
324✔
1370

1371
   vlog_range_kind_t kind = V_RANGE_CONST;
162✔
1372
   switch (one_of(tCOLON, tINDEXPOS, tINDEXNEG)) {
162✔
1373
   case tINDEXPOS: kind = V_RANGE_POS; break;
16✔
1374
   case tINDEXNEG: kind = V_RANGE_NEG; break;
3✔
1375
   }
1376

1377
   vlog_set_subkind(ps, kind);
162✔
1378
   vlog_set_right(ps, p_constant_expression());
162✔
1379
}
162✔
1380

1381
static vlog_node_t p_hierarchical_identifier(ident_t id)
10✔
1382
{
1383
   // [ $root . ] { identifier constant_bit_select . } identifier
1384

1385
   EXTEND("hierarchical identifier");
10✔
1386

1387
   if (id == NULL)
10✔
1388
      id = p_identifier();
3✔
1389

1390
   vlog_node_t v = vlog_new(V_HIER_REF);
10✔
1391
   vlog_set_ident(v, id);
10✔
1392

1393
   consume(tDOT);
10✔
1394

1395
   ident_t suffix = NULL;
10✔
1396
   do {
11✔
1397
      suffix = ident_prefix(suffix, p_identifier(), '.');
11✔
1398
      vlog_set_ident2(v, suffix);
11✔
1399
   } while (optional(tDOT));
11✔
1400

1401
   vlog_set_loc(v, CURRENT_LOC);
10✔
1402
   vlog_symtab_lookup(symtab, v);
10✔
1403
   return v;
10✔
1404
}
1405

1406
static vlog_node_t p_select(ident_t id)
6,277✔
1407
{
1408
   // [ { . member_identifier bit_select } . member_identifier ]
1409
   //    { [ expression ] } [ [ part_select_range ] ]
1410

1411
   EXTEND("select");
12,554✔
1412

1413
   vlog_node_t d = vlog_symtab_query(symtab, id), prefix;
6,277✔
1414
   if (d != NULL && vlog_kind(d) == V_MOD_INST)
6,277✔
1415
      prefix = p_hierarchical_identifier(id);
2✔
1416
   else if (d == NULL && peek() == tDOT) {
6,275✔
1417
      // Assume this is a hierarchical reference to a later instance
1418
      prefix = p_hierarchical_identifier(id);
5✔
1419
   }
1420
   else {
1421
      prefix = vlog_new(V_REF);
6,270✔
1422
      vlog_set_ident(prefix, id);
6,270✔
1423
      vlog_set_loc(prefix, CURRENT_LOC);
6,270✔
1424

1425
      vlog_symtab_lookup(symtab, prefix);
6,270✔
1426

1427
      while (optional(tDOT)) {
6,339✔
1428
         vlog_node_t ref = vlog_new(V_MEMBER_REF);
69✔
1429
         vlog_set_ident(ref, p_identifier());
69✔
1430
         vlog_set_value(ref, prefix);
69✔
1431
         vlog_set_loc(ref, CURRENT_LOC);
69✔
1432

1433
         vlog_symtab_lookup(symtab, ref);
69✔
1434

1435
         prefix = ref;
69✔
1436
      }
1437
   }
1438

1439
   if (optional(tLSQUARE)) {
6,277✔
1440
      do {
423✔
1441
         vlog_node_t expr = p_expression();
423✔
1442
         if (scan(tCOLON, tINDEXPOS, tINDEXNEG)) {
423✔
1443
            vlog_node_t ps = vlog_new(V_PART_SELECT);
162✔
1444
            vlog_set_left(ps, expr);
162✔
1445
            vlog_set_value(ps, prefix);
162✔
1446

1447
            p_part_select_range(ps);
162✔
1448

1449
            consume(tRSQUARE);
162✔
1450

1451
            vlog_set_loc(ps, CURRENT_LOC);
162✔
1452
            return ps;
162✔
1453
         }
1454

1455
         if (vlog_kind(prefix) == V_BIT_SELECT)
261✔
1456
            vlog_add_param(prefix, expr);
57✔
1457
         else {
1458
            vlog_node_t bs = vlog_new(V_BIT_SELECT);
204✔
1459
            vlog_set_loc(bs, CURRENT_LOC);
204✔
1460
            vlog_set_value(bs, prefix);
204✔
1461
            vlog_add_param(bs, expr);
204✔
1462

1463
            prefix = bs;
204✔
1464
         }
1465

1466
         consume(tRSQUARE);
261✔
1467
      } while (optional(tLSQUARE));
261✔
1468
   }
1469

1470
   return prefix;
1471
}
1472

1473
static void p_list_of_arguments(vlog_node_t call)
1,375✔
1474
{
1475
   // [ expression ] { , [ expression ] } { , . identifier ( [ expression ] ) }
1476
   //    | . identifier ( [ expression ] ) { , . identifier ( [ expression ] ) }
1477

1478
   BEGIN("list of arguments");
2,743✔
1479

1480
   if (peek() == tRPAREN)
1,375✔
1481
      return;
7✔
1482

1483
   do {
2,673✔
1484
      if (peek() == tCOMMA) {
2,673✔
1485
         vlog_node_t v = vlog_new(V_EMPTY);
162✔
1486
         vlog_set_loc(v, &state.last_loc);
162✔
1487
         vlog_add_param(call, v);
162✔
1488
      }
1489
      else
1490
         vlog_add_param(call, p_expression());
2,511✔
1491
   } while (optional(tCOMMA));
2,673✔
1492
}
1493

1494
static vlog_node_t p_system_tf_call(vlog_kind_t kind)
1,614✔
1495
{
1496
   // system_tf_identifier [ ( list_of_arguments ) ]
1497

1498
   BEGIN("system task or function call");
1,614✔
1499

1500
   vlog_node_t v = vlog_new(kind);
1,614✔
1501
   vlog_set_ident(v, p_system_tf_identifier());
1,614✔
1502

1503
   if (optional(tLPAREN)) {
1,614✔
1504
      p_list_of_arguments(v);
1,221✔
1505
      consume(tRPAREN);
1,221✔
1506
   }
1507

1508
   vlog_set_loc(v, CURRENT_LOC);
1,614✔
1509
   return v;
1,614✔
1510
}
1511

1512
static vlog_node_t p_tf_call(vlog_kind_t kind)
154✔
1513
{
1514
   // ps_or_hierarchical_tf_identifier { attribute_instance }
1515
   //    [ ( list_of_arguments ) ]
1516

1517
   BEGIN("task or function call");
154✔
1518

1519
   vlog_node_t v = vlog_new(kind);
154✔
1520
   vlog_set_ident(v, p_identifier());
154✔
1521

1522
   optional_attributes();
154✔
1523

1524
   if (optional(tLPAREN)) {
154✔
1525
      p_list_of_arguments(v);
151✔
1526
      consume(tRPAREN);
151✔
1527
   }
1528

1529
   vlog_set_loc(v, CURRENT_LOC);
154✔
1530
   vlog_symtab_lookup(symtab, v);
154✔
1531
   return v;
154✔
1532
}
1533

1534
static vlog_node_t p_subroutine_call(vlog_kind_t kind)
1,768✔
1535
{
1536
   // tf_call | system_tf_call | method_call | [ std:: ] randomize_call
1537

1538
   BEGIN("subroutine call");
3,536✔
1539

1540
   if (peek() == tSYSTASK)
1,768✔
1541
      return p_system_tf_call(kind);
1,614✔
1542
   else
1543
      return p_tf_call(kind);
154✔
1544
}
1545

1546
static vlog_node_t p_mintypmax_expression(void)
245✔
1547
{
1548
   // expression | expression : expression : expression
1549

1550
   BEGIN("mintypmax expression");
490✔
1551

1552
   vlog_node_t e = p_expression();
245✔
1553

1554
   if (optional(tCOLON)) {
245✔
1555
      vlog_node_t mtm = vlog_new(V_MIN_TYP_MAX);
1✔
1556
      vlog_set_left(mtm, e);
1✔
1557
      vlog_set_value(mtm, p_expression());
1✔
1558

1559
      consume(tCOLON);
1✔
1560
      vlog_set_right(mtm, p_expression());
1✔
1561

1562
      return mtm;
1✔
1563
   }
1564

1565
   return e;
1566
}
1567

1568
static vlog_node_t p_concatenation(vlog_node_t head)
87✔
1569
{
1570
   // { expression { , expression } }
1571

1572
   BEGIN_WITH_HEAD("concatenation", head);
87✔
1573

1574
   if (head == NULL) {
87✔
1575
      consume(tLBRACE);
30✔
1576
      head = p_expression();
30✔
1577
   }
1578

1579
   vlog_node_t v = vlog_new(V_CONCAT);
87✔
1580
   vlog_add_param(v, head);
87✔
1581

1582
   while (optional(tCOMMA))
183✔
1583
      vlog_add_param(v, p_expression());
96✔
1584

1585
   consume(tRBRACE);
87✔
1586

1587
   vlog_set_loc(v, CURRENT_LOC);
87✔
1588
   return v;
87✔
1589
}
1590

1591
static vlog_node_t p_multiple_concatenation(vlog_node_t head)
30✔
1592
{
1593
   // { expression concatenation }
1594

1595
   BEGIN_WITH_HEAD("multiple concatenation", head);
30✔
1596

1597
   vlog_node_t v = p_concatenation(NULL);
30✔
1598
   vlog_set_value(v, head);
30✔
1599

1600
   consume(tRBRACE);
30✔
1601

1602
   vlog_set_loc(v, CURRENT_LOC);
30✔
1603
   return v;
30✔
1604
}
1605

1606
static vlog_node_t p_primary(void)
10,195✔
1607
{
1608
   // primary_literal | empty_queue
1609
   // | [ class_qualifier | package_scope ] hierarchical_identifier select
1610
   // | concatenation [ [ range_expression ] ]
1611
   // | multiple_concatenation [ [ range_expression ] ]
1612
   // | function_subroutine_call
1613
   // | let_expression | ( mintypmax_expression ) | cast
1614
   // | assignment_pattern_expression | streaming_concatenation
1615
   // | sequence_method_call | this | $ | null
1616

1617
   BEGIN("primary");
20,390✔
1618

1619
   switch (peek()) {
10,195✔
1620
   case tID:
4,147✔
1621
      switch (peek_nth(2)) {
4,147✔
1622
      case tLPAREN:
142✔
1623
      case tATTRBEGIN:
1624
         return p_subroutine_call(V_USER_FCALL);
142✔
1625
      default:
4,005✔
1626
         return p_select(p_identifier());
4,005✔
1627
      }
1628
   case tSTRING:
5,579✔
1629
   case tNUMBER:
1630
   case tUNSNUM:
1631
   case tREAL:
1632
      return p_primary_literal();
5,579✔
1633
   case tSYSTASK:
224✔
1634
      return p_subroutine_call(V_SYS_FCALL);
224✔
1635
   case tLPAREN:
144✔
1636
      {
1637
         consume(tLPAREN);
144✔
1638
         vlog_node_t expr = p_mintypmax_expression();
144✔
1639
         consume(tRPAREN);
144✔
1640
         return expr;
144✔
1641
      }
1642
   case tLBRACE:
87✔
1643
      {
1644
         consume(tLBRACE);
87✔
1645

1646
         vlog_node_t head = p_expression();
87✔
1647
         if (peek() == tLBRACE)
87✔
1648
            return p_multiple_concatenation(head);
30✔
1649
         else
1650
            return p_concatenation(head);
57✔
1651
      }
1652
   case tNULL:
14✔
1653
      {
1654
         consume(tNULL);
14✔
1655

1656
         vlog_node_t v = vlog_new(V_NULL);
14✔
1657
         vlog_set_loc(v, CURRENT_LOC);
14✔
1658
         return v;
14✔
1659
      }
1660

UNCOV
1661
   default:
×
UNCOV
1662
      one_of(tID, tSTRING, tNUMBER, tUNSNUM, tREAL, tSYSTASK, tLPAREN,
×
1663
             tLBRACE, tNULL);
UNCOV
1664
      return p_select(error_marker());
×
1665
   }
1666
}
1667

1668
static vlog_binary_t p_binary_operator(void)
1,936✔
1669
{
1670
   // + | - | * | / | % | == | != | === | !== | ==? | !=? | && | ||
1671
   //  | ** | < | <= | > | >= | & | | | ^ | ^~ | ~^ | >> | <<
1672
   //  | >>> | <<< | -> | <->
1673

1674
   BEGIN("binary operator");
3,872✔
1675

1676
   switch (one_of(tBAR, tPLUS, tAMP, tCASEEQ, tCASENEQ, tLOGOR,
1,936✔
1677
                  tLOGEQ, tLOGNEQ, tDBLAMP, tSHIFTLL, tSHIFTRL,
1678
                  tSHIFTLA, tSHIFTRA, tLT, tGT, tLE, tGE, tMINUS,
1679
                  tTIMES, tOVER, tPERCENT, tPOWER, tCARET, tTILDECARET,
1680
                  tTILDEAMP)) {
1681
   case tBAR:        return V_BINARY_OR;
1682
   case tAMP:        return V_BINARY_AND;
46✔
1683
   case tCASEEQ:     return V_BINARY_CASE_EQ;
219✔
1684
   case tCASENEQ:    return V_BINARY_CASE_NEQ;
556✔
1685
   case tLOGEQ:      return V_BINARY_LOG_EQ;
118✔
1686
   case tLOGNEQ:     return V_BINARY_LOG_NEQ;
63✔
1687
   case tLOGOR:      return V_BINARY_LOG_OR;
230✔
1688
   case tDBLAMP:     return V_BINARY_LOG_AND;
113✔
1689
   case tSHIFTLL:    return V_BINARY_SHIFT_LL;
26✔
1690
   case tSHIFTRL:    return V_BINARY_SHIFT_RL;
17✔
1691
   case tSHIFTLA:    return V_BINARY_SHIFT_LA;
8✔
1692
   case tSHIFTRA:    return V_BINARY_SHIFT_RA;
20✔
1693
   case tLT:         return V_BINARY_LT;
61✔
1694
   case tGT:         return V_BINARY_GT;
16✔
1695
   case tLE:         return V_BINARY_LEQ;
15✔
1696
   case tGE:         return V_BINARY_GEQ;
18✔
1697
   case tMINUS:      return V_BINARY_MINUS;
154✔
1698
   case tTIMES:      return V_BINARY_TIMES;
57✔
1699
   case tOVER:       return V_BINARY_DIVIDE;
30✔
1700
   case tPERCENT:    return V_BINARY_MOD;
8✔
1701
   case tPOWER:      return V_BINARY_EXP;
4✔
1702
   case tCARET:      return V_BINARY_XOR;
9✔
1703
   case tTILDECARET: return V_BINARY_XNOR;
5✔
UNCOV
1704
   case tTILDEAMP:   return V_BINARY_NAND;
×
1705
   case tPLUS:
117✔
1706
   default:          return V_BINARY_PLUS;
117✔
1707
   }
1708
}
1709

1710
static vlog_unary_t p_unary_operator(void)
203✔
1711
{
1712
   // + | - | ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~
1713

1714
   BEGIN("unary operator");
406✔
1715

1716
   switch (one_of(tMINUS, tPLUS, tTILDE, tBANG, tAMP, tBAR, tCARET,
203✔
1717
                  tTILDEAMP, tTILDEBAR, tTILDECARET)) {
1718
   case tMINUS:      return V_UNARY_NEG;
1719
   case tTILDE:      return V_UNARY_BITNEG;
45✔
1720
   case tBANG:       return V_UNARY_NOT;
46✔
1721
   case tAMP:        return V_UNARY_AND;
10✔
1722
   case tBAR:        return V_UNARY_OR;
7✔
1723
   case tCARET:      return V_UNARY_XOR;
7✔
1724
   case tTILDEAMP:   return V_UNARY_NAND;
4✔
1725
   case tTILDEBAR:   return V_UNARY_NOR;
3✔
UNCOV
1726
   case tTILDECARET: return V_UNARY_XNOR;
×
1727
   case tPLUS:
8✔
1728
   default:          return V_UNARY_IDENTITY;
8✔
1729
   }
1730
}
1731

1732
static vlog_incdec_t p_inc_or_dec_operator(void)
24✔
1733
{
1734
   // ++ | --
1735

1736
   BEGIN("inc or dec operator");
48✔
1737

1738
   switch (one_of(tPLUSPLUS, tMINUSMINUS)) {
24✔
1739
   case tMINUSMINUS: return V_INCDEC_MINUS;
1740
   case tPLUSPLUS:
23✔
1741
   default: return V_INCDEC_PLUS;
23✔
1742
   }
1743
}
1744

1745
static vlog_node_t p_inc_or_dec_expression(vlog_node_t head)
22✔
1746
{
1747
   // inc_or_dec_operator { attribute_instance } variable_lvalue
1748
   //   | variable_lvalue { attribute_instance } inc_or_dec_operator
1749

1750
   BEGIN_WITH_HEAD("inc or dec expression", head);
22✔
1751

1752
   vlog_node_t v = vlog_new(head ? V_POSTFIX : V_PREFIX);
27✔
1753
   vlog_set_subkind(v, p_inc_or_dec_operator());
22✔
1754
   vlog_set_target(v, head ?: p_variable_lvalue());
22✔
1755

1756
   vlog_set_loc(v, CURRENT_LOC);
22✔
1757
   return v;
22✔
1758
}
1759

1760
static vlog_node_t p_nonbinary_expression(void)
10,200✔
1761
{
1762
   // primary | unary_operator { attribute_instance } primary
1763
   //   | inc_or_dec_expression | ( operator_assignment )
1764
   //   | conditional_expression | inside_expression | tagged_union_expression
1765

1766
   switch (peek()) {
10,200✔
1767
   case tID:
9,992✔
1768
   case tSTRING:
1769
   case tNUMBER:
1770
   case tUNSNUM:
1771
   case tREAL:
1772
   case tSYSTASK:
1773
   case tLPAREN:
1774
   case tLBRACE:
1775
   case tNULL:
1776
      return p_primary();
9,992✔
1777
   case tMINUS:
203✔
1778
   case tPLUS:
1779
   case tTILDE:
1780
   case tBANG:
1781
   case tAMP:
1782
   case tBAR:
1783
   case tCARET:
1784
   case tTILDEAMP:
1785
   case tTILDEBAR:
1786
   case tTILDECARET:
1787
      {
1788
         vlog_node_t v = vlog_new(V_UNARY);
203✔
1789
         vlog_set_subkind(v, p_unary_operator());
203✔
1790

1791
         optional_attributes();
203✔
1792

1793
         vlog_set_value(v, p_primary());
203✔
1794
         vlog_set_loc(v, CURRENT_LOC);
203✔
1795
         return v;
203✔
1796
      }
1797
   case tPLUSPLUS:
4✔
1798
   case tMINUSMINUS:
1799
      return p_inc_or_dec_expression(NULL);
4✔
1800
   default:
1✔
1801
      one_of(tID, tSTRING, tNUMBER, tUNSNUM, tREAL, tSYSTASK, tLPAREN,
1✔
1802
             tLBRACE, tNULL, tMINUS, tTILDE, tBANG, tAMP, tBAR, tCARET,
1803
             tTILDEAMP, tTILDEBAR, tPLUSPLUS, tTILDECARET, tMINUSMINUS);
1804
      return p_select(error_marker());
1✔
1805
   }
1806
}
1807

1808
static vlog_node_t p_conditional_expression(vlog_node_t head)
34✔
1809
{
1810
   // cond_predicate ? { attribute_instance } expression : expression
1811

1812
   BEGIN_WITH_HEAD("conditional expression", head);
34✔
1813

1814
   vlog_node_t v = vlog_new(V_COND_EXPR);
34✔
1815
   vlog_set_value(v, head);
34✔
1816

1817
   consume(tQUESTION);
34✔
1818

1819
   optional_attributes();
34✔
1820

1821
   vlog_set_left(v, p_expression());
34✔
1822

1823
   consume(tCOLON);
34✔
1824

1825
   vlog_set_right(v, p_expression());
34✔
1826

1827
   vlog_set_loc(v, CURRENT_LOC);
34✔
1828
   return v;
34✔
1829
}
1830

1831
static bool peek_binary_operator(int *prec)
12,812✔
1832
{
1833
   // See LRM 1800-2017 section 11.3.2 for operator precedence table
1834

1835
   switch (peek()) {
12,812✔
1836
   case tPOWER:      *prec = 12; return true;
4✔
1837
   case tTIMES:
102✔
1838
   case tOVER:
1839
   case tPERCENT:    *prec = 11; return true;
102✔
1840
   case tPLUS:
302✔
1841
   case tMINUS:      *prec = 10; return true;
302✔
1842
   case tSHIFTLL:
73✔
1843
   case tSHIFTRL:
1844
   case tSHIFTLA:
1845
   case tSHIFTRA:    *prec = 9;  return true;
73✔
1846
   case tLT:
110✔
1847
   case tGT:
1848
   case tLE:
1849
   case tGE:         *prec = 8;  return true;
110✔
1850
   case tCASEEQ:
1,269✔
1851
   case tCASENEQ:
1852
   case tLOGEQ:
1853
   case tLOGNEQ:     *prec = 7;  return true;
1,269✔
1854
   case tAMP:        *prec = 6;  return true;
48✔
1855
   case tTILDECARET:
14✔
1856
   case tCARET:      *prec = 5;  return true;
14✔
1857
   case tBAR:        *prec = 4;  return true;
27✔
1858
   case tDBLAMP:     *prec = 3;  return true;
284✔
1859
   case tLOGOR:      *prec = 2;  return true;
675✔
1860
   case tQUESTION:   *prec = 1;  return true;
39✔
1861
   default:
1862
      return false;
1863
   }
1864
}
1865

1866
static vlog_node_t p_binary_expression(vlog_node_t lhs, int min_prec)
8,585✔
1867
{
1868
   // Precedence climbing method, see
1869
   //    https://en.wikipedia.org/wiki/Operator-precedence_parser
1870

1871
   int prec1;
8,585✔
1872
   while (peek_binary_operator(&prec1) && prec1 >= min_prec) {
10,555✔
1873
      if (peek() == tQUESTION)
1,970✔
1874
         lhs = p_conditional_expression(lhs);
34✔
1875
      else {
1876
         vlog_node_t v = vlog_new(V_BINARY);
1,936✔
1877
         vlog_set_subkind(v, p_binary_operator());
1,936✔
1878
         vlog_set_left(v, lhs);
1,936✔
1879

1880
         optional_attributes();
1,936✔
1881

1882
         vlog_node_t rhs = p_nonbinary_expression();
1,936✔
1883

1884
         int prec2;
1,936✔
1885
         while (peek_binary_operator(&prec2) && prec2 > prec1)
2,257✔
1886
            rhs = p_binary_expression(rhs, prec1 + (prec2 > prec1));
321✔
1887

1888
         vlog_set_right(v, rhs);
1,936✔
1889
         vlog_set_loc(v, CURRENT_LOC);
1,936✔
1890
         lhs = v;
1,936✔
1891
      }
1892
   }
1893

1894
   return lhs;
8,585✔
1895
}
1896

1897
static vlog_node_t p_expression(void)
8,264✔
1898
{
1899
   // primary | unary_operator { attribute_instance } primary
1900
   //   | inc_or_dec_expression | ( operator_assignment )
1901
   //   | expression binary_operator { attribute_instance } expression
1902
   //   | conditional_expression | inside_expression | tagged_union_expression
1903

1904
   BEGIN("expression");
16,528✔
1905

1906
   vlog_node_t head = p_nonbinary_expression();
8,264✔
1907
   return p_binary_expression(head, 0);
8,264✔
1908
}
1909

1910
static void p_event_expression(vlog_node_t ctrl)
120✔
1911
{
1912
   // [ edge_identifier ] expression [ iff expression ]
1913
   //   | sequence_instance [ iff expression ]
1914
   //   | event_expression or event_expression
1915
   //   | event_expression , event_expression
1916
   //   | ( event_expression )
1917

1918
   BEGIN("event expression");
240✔
1919

1920
   do {
140✔
1921
      if (optional(tLPAREN)) {
140✔
1922
         p_event_expression(ctrl);
1✔
1923
         consume(tRPAREN);
1✔
1924
      }
1925
      else {
1926
         vlog_node_t v = vlog_new(V_EVENT);
139✔
1927

1928
         if (optional(tPOSEDGE))
139✔
1929
            vlog_set_subkind(v, V_EVENT_POSEDGE);
32✔
1930
         else if (optional(tNEGEDGE))
107✔
1931
            vlog_set_subkind(v, V_EVENT_NEGEDGE);
15✔
1932
         else
1933
            vlog_set_subkind(v, V_EVENT_LEVEL);
92✔
1934

1935
         vlog_set_value(v, p_expression());
139✔
1936
         vlog_set_loc(v, CURRENT_LOC);
139✔
1937

1938
         vlog_add_param(ctrl, v);
139✔
1939
      }
1940
   } while (optional(tOR) || optional(tCOMMA));
140✔
1941
}
120✔
1942

1943
static vlog_node_t p_cond_predicate(void)
667✔
1944
{
1945
   // expression_or_cond_pattern { &&& expression_or_cond_pattern }
1946

1947
   BEGIN("cond predicate");
1,334✔
1948

1949
   return p_expression();
667✔
1950
}
1951

1952
static vlog_node_t p_event_control(void)
160✔
1953
{
1954
   // @ hierarchical_event_identifier | @ ( event_expression )
1955
   //    | @* | @ (*) | @ ps_or_hierarchical_sequence_identifier
1956

1957
   BEGIN("event control");
160✔
1958

1959
   consume(tAT);
160✔
1960

1961
   vlog_node_t v = vlog_new(V_EVENT_CONTROL);
160✔
1962

1963
   switch (one_of(tLPAREN, tTIMES, tPARENSTAR)) {
160✔
1964
   case tLPAREN:
120✔
1965
      if (peek() == tATTREND)
120✔
1966
         consume(tATTREND);   // Lexing ambiguity
1✔
1967
      else {
1968
         p_event_expression(v);
119✔
1969
         consume(tRPAREN);
119✔
1970
      }
1971
      break;
1972
   case tTIMES:
1973
   case tPARENSTAR:
1974
      break;
1975
   }
1976

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

1981
static vlog_node_t p_delay_value(void)
670✔
1982
{
1983
   // unsigned_number | real_number | ps_identifier | time_literal | 1step
1984

1985
   BEGIN("delay value");
1,340✔
1986

1987
   switch (peek()) {
670✔
1988
   case tREAL:
4✔
1989
      return p_real_number();
4✔
1990
   case tID:
1✔
1991
      {
1992
         vlog_node_t v = vlog_new(V_REF);
1✔
1993
         vlog_set_ident(v, p_identifier());
1✔
1994
         vlog_set_loc(v, CURRENT_LOC);
1✔
1995

1996
         vlog_symtab_lookup(symtab, v);
1✔
1997
         return v;
1✔
1998
      }
1999
   case tUNSNUM:
665✔
2000
   default:
2001
      return p_unsigned_number();
665✔
2002
   }
2003
}
2004

2005
static vlog_node_t p_delay_control(void)
668✔
2006
{
2007
   // # delay_value | # ( mintypmax_expression )
2008

2009
   BEGIN("delay control");
668✔
2010

2011
   consume(tHASH);
668✔
2012

2013
   vlog_node_t v = vlog_new(V_DELAY_CONTROL);
668✔
2014

2015
   if (peek() != tLPAREN)
668✔
2016
      vlog_set_value(v, p_delay_value());
665✔
2017
   else
2018
      vlog_set_value(v, p_mintypmax_expression());
3✔
2019

2020
   vlog_set_loc(v, CURRENT_LOC);
668✔
2021
   return v;
668✔
2022
}
2023

2024
static void p_delay3(void)
7✔
2025
{
2026
   // # delay_value | # ( mintypmax_expression [ , mintypmax_expression
2027
   //   [ , mintypmax_expression ] ] )
2028

2029
   BEGIN("delay3");
14✔
2030

2031
   consume(tHASH);
7✔
2032

2033
   if (peek() != tLPAREN)
7✔
2034
      p_delay_value();
3✔
2035
   else {
2036
      consume(tLPAREN);
4✔
2037

2038
      int expr_cnt = 0;
4✔
2039
      do {
12✔
2040
         (void)p_mintypmax_expression();
12✔
2041
         expr_cnt++;
12✔
2042
      } while (optional(tCOMMA) && (expr_cnt < 3));
12✔
2043

2044
      consume(tRPAREN);
4✔
2045
   }
2046
}
7✔
2047

2048
static void p_delay2(void)
2✔
2049
{
2050
   // # delay_value | # ( mintypmax_expression [ , mintypmax_expression ] )
2051

2052
   BEGIN("delay2");
4✔
2053

2054
   consume(tHASH);
2✔
2055

2056
   if (peek() != tLPAREN)
2✔
2057
      p_delay_value();
1✔
2058
   else {
2059
      consume(tLPAREN);
1✔
2060

2061
      (void)p_mintypmax_expression();
1✔
2062

2063
      if (optional(tCOMMA))
1✔
2064
         (void)p_mintypmax_expression();
1✔
2065

2066
      consume(tRPAREN);
1✔
2067
   }
2068
}
2✔
2069

2070
static vlog_node_t p_delay_or_event_control(void)
38✔
2071
{
2072
   // delay_control | event_control | repeat ( expression ) event_control
2073

2074
   BEGIN("delay or event control");
76✔
2075

2076
   return p_delay_control();
38✔
2077
}
2078

2079
static vlog_node_t p_variable_lvalue(void)
1,972✔
2080
{
2081
   // [ implicit_class_handle . | package_scope ]
2082
   //      hierarchical_variable_identifier select
2083
   //   | { variable_lvalue { , variable_lvalue } }
2084
   //   | [ assignment_pattern_expression_type ]
2085
   //      assignment_pattern_variable_lvalue
2086
   //   | streaming_concatenation
2087

2088
   BEGIN("variable lvalue");
3,944✔
2089

2090
   if (optional(tLBRACE)) {
1,972✔
2091
      vlog_node_t v = vlog_new(V_CONCAT);
4✔
2092

2093
      do {
11✔
2094
         vlog_add_param(v, p_variable_lvalue());
11✔
2095
      } while (optional(tCOMMA));
11✔
2096

2097
      consume(tRBRACE);
4✔
2098

2099
      vlog_set_loc(v, CURRENT_LOC);
4✔
2100
      return v;
4✔
2101
   }
2102
   else {
2103
      ident_t id = p_identifier();
1,968✔
2104
      vlog_node_t v = p_select(id);
1,968✔
2105

2106
      vlog_set_loc(v, CURRENT_LOC);
1,968✔
2107
      return v;
1,968✔
2108
   }
2109
}
2110

2111
static vlog_node_t p_net_lvalue(void)
309✔
2112
{
2113
   // ps_or_hierarchical_net_identifier constant_select
2114
   //   | { net_lvalue { , net_lvalue } }
2115
   //   | [ assignment_pattern_expression_type ] assignment_pattern_net_lvalue
2116

2117
   BEGIN("net lvalue");
618✔
2118

2119
   if (optional(tLBRACE)) {
309✔
2120
      vlog_node_t v = vlog_new(V_CONCAT);
6✔
2121

2122
      do {
12✔
2123
         vlog_add_param(v, p_net_lvalue());
12✔
2124
      } while (optional(tCOMMA));
12✔
2125

2126
      consume(tRBRACE);
6✔
2127

2128
      vlog_set_loc(v, CURRENT_LOC);
6✔
2129
      return v;
6✔
2130
   }
2131
   else {
2132
      ident_t id = p_identifier();
303✔
2133
      vlog_node_t v = p_constant_select(id);
303✔
2134

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

2140
static vlog_node_t p_class_new(vlog_node_t dt)
7✔
2141
{
2142
   // [ class_scope ] new [ ( list_of_arguments ) ]
2143
   //    | new expression
2144

2145
   BEGIN("class new");
7✔
2146

2147
   consume(tNEW);
7✔
2148

2149
   if (dt == NULL || vlog_kind(dt) != V_CLASS_DECL) {
7✔
2150
      error_at(&state.last_loc, "new class expression must have class type");
1✔
2151
      dt = NULL;
1✔
2152
   }
2153

2154
   vlog_node_t v = vlog_new(V_CLASS_NEW);
7✔
2155
   vlog_set_type(v, dt);
7✔
2156

2157
   if (optional(tLPAREN)) {
7✔
2158
      p_list_of_arguments(v);
2✔
2159
      consume(tRPAREN);
2✔
2160
   }
2161

2162
   vlog_set_loc(v, CURRENT_LOC);
7✔
2163
   return v;
7✔
2164
}
2165

2166
static vlog_assign_t p_assignment_operator(void)
96✔
2167
{
2168
   // = | += | -= | *= | /= | %= | &= | |= | ^= | <<= | >>= | <<<= | >>>=
2169

2170
   BEGIN("assignment operator");
192✔
2171

2172
   switch (one_of(tEQ, tPLUSEQ, tMINUSEQ, tTIMESEQ, tDIVEQ, tPERCENTEQ, tAMPEQ,
96✔
2173
                  tBAREQ, tCARETEQ, tLSLEQ, tLSREQ, tASLEQ, tASREQ)) {
2174
   case tPLUSEQ:    return V_ASSIGN_PLUS;
2175
   case tMINUSEQ:   return V_ASSIGN_MINUS;
2176
   case tTIMESEQ:   return V_ASSIGN_TIMES;
2177
   case tDIVEQ:     return V_ASSIGN_DIVIDE;
2178
   case tPERCENTEQ: return V_ASSIGN_MOD;
2179
   case tAMPEQ:     return V_ASSIGN_AND;
2180
   case tBAREQ:     return V_ASSIGN_OR;
2181
   case tCARETEQ:   return V_ASSIGN_XOR;
2182
   case tLSLEQ:     return V_ASSIGN_SHIFT_LL;
2183
   case tLSREQ:     return V_ASSIGN_SHIFT_RL;
2184
   case tASLEQ:     return V_ASSIGN_SHIFT_LA;
2185
   case tASREQ:     return V_ASSIGN_SHIFT_RA;
2186
   default:         return V_ASSIGN_EQUALS;
2187
   }
2188
}
2189

2190
static vlog_node_t p_operator_assignment(vlog_node_t lhs)
96✔
2191
{
2192
   // variable_lvalue assignment_operator expression
2193

2194
   BEGIN_WITH_HEAD("operator assignment", lhs);
96✔
2195

2196
   vlog_node_t v = vlog_new(V_OP_ASSIGN);
96✔
2197
   vlog_set_subkind(v, p_assignment_operator());
96✔
2198
   vlog_set_target(v, lhs);
96✔
2199

2200
   vlog_set_value(v, p_expression());
96✔
2201

2202
   vlog_set_loc(v, CURRENT_LOC);
96✔
2203
   return v;
96✔
2204
}
2205

2206
static vlog_node_t p_blocking_assignment(vlog_node_t lhs)
1,716✔
2207
{
2208
   // variable_lvalue = delay_or_event_control expression
2209
   //   | nonrange_variable_lvalue = dynamic_array_new
2210
   //   | [ implicit_class_handle . | class_scope | package_scope ]
2211
   //         hierarchical_variable_identifier select = class_new
2212
   //   | operator_assignment
2213

2214
   BEGIN_WITH_HEAD("blocking assignment", lhs);
3,432✔
2215

2216
   switch (peek()) {
1,716✔
2217
   case tPLUSEQ:
65✔
2218
   case tMINUSEQ:
2219
   case tTIMESEQ:
2220
   case tDIVEQ:
2221
   case tPERCENTEQ:
2222
   case tAMPEQ:
2223
   case tBAREQ:
2224
   case tCARETEQ:
2225
   case tLSLEQ:
2226
   case tLSREQ:
2227
   case tASLEQ:
2228
   case tASREQ:
2229
      return p_operator_assignment(lhs);
65✔
2230
   }
2231

2232
   consume(tEQ);
1,651✔
2233

2234
   vlog_node_t v = vlog_new(V_BASSIGN);
1,651✔
2235
   vlog_set_target(v, lhs);
1,651✔
2236

2237
   if (peek() == tNEW)
1,651✔
2238
      vlog_set_value(v, p_class_new(vlog_get_type(lhs)));
7✔
2239
   else {
2240
      if (scan(tHASH, tAT))
1,644✔
2241
         vlog_set_delay(v, p_delay_or_event_control());
25✔
2242

2243
      vlog_set_value(v, p_expression());
1,644✔
2244
   }
2245

2246
   vlog_set_loc(v, CURRENT_LOC);
1,651✔
2247
   return v;
1,651✔
2248
}
2249

2250
static vlog_node_t p_nonblocking_assignment(vlog_node_t lhs)
144✔
2251
{
2252
   // variable_lvalue <= [ delay_or_event_control ] expression
2253

2254
   BEGIN_WITH_HEAD("non-blocking assignment", lhs);
144✔
2255

2256
   consume(tLE);
144✔
2257

2258
   vlog_node_t v = vlog_new(V_NBASSIGN);
144✔
2259
   vlog_set_target(v, lhs);
144✔
2260

2261
   if (scan(tHASH, tAT))
144✔
2262
      vlog_set_delay(v, p_delay_or_event_control());
13✔
2263

2264
   vlog_set_value(v, p_expression());
144✔
2265

2266
   vlog_set_loc(v, CURRENT_LOC);
144✔
2267
   return v;
144✔
2268
}
2269

2270
static vlog_node_t p_procedural_timing_control(void)
784✔
2271
{
2272
   // delay_control | event_control | cycle_delay
2273

2274
   BEGIN("procedural timing control");
1,568✔
2275

2276
   switch (peek()) {
784✔
2277
   case tAT:
160✔
2278
      return p_event_control();
160✔
2279
   case tHASH:
624✔
2280
      return p_delay_control();
624✔
UNCOV
2281
   default:
×
2282
      should_not_reach_here();
2283
   }
2284
}
2285

2286
static vlog_node_t p_procedural_timing_control_statement(void)
784✔
2287
{
2288
   // procedural_timing_control statement_or_null
2289

2290
   BEGIN("procedural timing control statement");
784✔
2291

2292
   vlog_node_t v = vlog_new(V_TIMING);
784✔
2293
   vlog_set_value(v, p_procedural_timing_control());
784✔
2294

2295
   vlog_node_t s = p_statement_or_null();
784✔
2296
   if (s != NULL)
784✔
2297
      vlog_add_stmt(v, s);
300✔
2298

2299
   vlog_set_loc(v, CURRENT_LOC);
784✔
2300
   return v;
784✔
2301
}
2302

2303
static vlog_node_t p_seq_block(ident_t id)
795✔
2304
{
2305
   // begin [ : block_identifier ] { block_item_declaration }
2306
   //   { statement_or_null } end [ : block_identifier ]
2307

2308
   BEGIN("sequential block");
795✔
2309

2310
   consume(tBEGIN);
795✔
2311

2312
   vlog_node_t v = vlog_new(V_BLOCK);
795✔
2313
   vlog_set_ident(v, id);
795✔
2314
   vlog_set_loc(v, CURRENT_LOC);
795✔
2315

2316
   vlog_symtab_push(symtab, v);
795✔
2317

2318
   if (optional(tCOLON)) {
795✔
2319
      ident_t name = p_identifier();
6✔
2320
      if (vlog_has_ident(v))
6✔
2321
         parse_error(&state.last_loc, "cannot specify both a statement label "
1✔
2322
                     "and a block name");
2323
      else
2324
         vlog_set_ident(v, name);
5✔
2325
   }
2326

2327
   skip_over_attributes();
795✔
2328

2329
   while (scan_block_item_declaration()) {
799✔
2330
      p_block_item_declaration(v);
4✔
2331
      skip_over_attributes();
4✔
2332
   }
2333

2334
   while (not_at_token(tEND)) {
4,626✔
2335
      vlog_node_t s = p_statement_or_null();
3,831✔
2336
      if (s != NULL)
3,831✔
2337
         vlog_add_stmt(v, s);
3,830✔
2338
   }
2339

2340
   vlog_symtab_pop(symtab);
795✔
2341

2342
   consume(tEND);
795✔
2343

2344
   if (optional(tCOLON)) {
795✔
2345
      ident_t name = p_identifier();
6✔
2346
      if (!vlog_has_ident(v))
6✔
2347
         parse_error(&state.last_loc, "initial block does not have a label");
1✔
2348
      else if (name != vlog_ident(v))
5✔
2349
         parse_error(&state.last_loc, "'%s' does not match label '%s'",
1✔
2350
                     istr(name), istr(vlog_ident(v)));
2351
   }
2352

2353
   return v;
795✔
2354
}
2355

2356
static vlog_node_t p_par_block(ident_t id)
7✔
2357
{
2358
   // fork [ : block_identifier ] { block_item_declaration }
2359
   //   { statement_or_null } join_keyword [ : block_identifier ]
2360

2361
   BEGIN("parallel block");
7✔
2362

2363
   consume(tFORK);
7✔
2364

2365
   vlog_node_t v = vlog_new(V_FORK);
7✔
2366
   vlog_set_ident(v, id);
7✔
2367
   vlog_set_loc(v, CURRENT_LOC);
7✔
2368

2369
   vlog_symtab_push(symtab, v);
7✔
2370

2371
   if (optional(tCOLON)) {
7✔
2372
      ident_t name = p_identifier();
4✔
2373
      if (vlog_has_ident(v))
4✔
2374
         parse_error(&state.last_loc, "cannot specify both a statement label "
1✔
2375
                     "and a block name");
2376
      else
2377
         vlog_set_ident(v, name);
3✔
2378
   }
2379

2380
   skip_over_attributes();
7✔
2381

2382
   while (scan_block_item_declaration()) {
9✔
2383
      p_block_item_declaration(v);
2✔
2384
      skip_over_attributes();
2✔
2385
   }
2386

2387
   while (not_at_token(tJOIN)) {
14✔
2388
      vlog_node_t s = p_statement_or_null();
7✔
2389
      if (s != NULL)
7✔
2390
         vlog_add_stmt(v, s);
7✔
2391
   }
2392

2393
   vlog_symtab_pop(symtab);
7✔
2394

2395
   consume(tJOIN);
7✔
2396

2397
   if (optional(tCOLON)) {
7✔
2398
      ident_t name = p_identifier();
5✔
2399
      if (!vlog_has_ident(v))
5✔
2400
         parse_error(&state.last_loc, "fork block does not have a label");
1✔
2401
      else if (name != vlog_ident(v))
4✔
2402
         parse_error(&state.last_loc, "'%s' does not match label '%s'",
1✔
2403
                     istr(name), istr(vlog_ident(v)));
2404
   }
2405

2406
   return v;
7✔
2407
}
2408

2409
static vlog_node_t p_subroutine_call_statement(void)
1,402✔
2410
{
2411
   // subroutine_call ; | void ' ( function_subroutine_call ) ;
2412

2413
   BEGIN("subroutine call statement");
1,402✔
2414

2415
   vlog_node_t v;
1,402✔
2416
   switch (peek()) {
1,402✔
2417
   case tSYSTASK:
1,390✔
2418
      v = p_subroutine_call(V_SYS_TCALL);
1,390✔
2419
      break;
1,390✔
2420
   case tVOID:
2✔
2421
      {
2422
         consume(tVOID);
2✔
2423
         consume(tTICK);
2✔
2424
         consume(tLPAREN);
2✔
2425

2426
         const vlog_kind_t kind =
4✔
2427
            peek() == tSYSTASK ? V_SYS_FCALL : V_USER_FCALL;
2✔
2428

2429
         v = vlog_new(V_VOID_CALL);
2✔
2430
         vlog_set_value(v, p_subroutine_call(kind));
2✔
2431

2432
         consume(tRPAREN);
2✔
2433
      }
2434
      break;
2✔
2435
   case tID:
10✔
2436
   default:
2437
      v = p_subroutine_call(V_USER_TCALL);
10✔
2438
      break;
10✔
2439
   }
2440

2441
   consume(tSEMI);
1,402✔
2442

2443
   vlog_set_loc(v, CURRENT_LOC);
1,402✔
2444
   return v;
1,402✔
2445
}
2446

2447
static vlog_node_t p_conditional_statement(void)
645✔
2448
{
2449
   // [ unique_priority ] if ( cond_predicate ) statement_or_null
2450
   //     { else if ( cond_predicate ) statement_or_null }
2451
   //     [ else statement_or_null ]
2452

2453
   BEGIN("conditional statement");
645✔
2454

2455
   vlog_node_t v = vlog_new(V_IF);
645✔
2456

2457
   consume(tIF);
645✔
2458
   consume(tLPAREN);
645✔
2459

2460
   vlog_node_t c0 = vlog_new(V_COND);
645✔
2461
   vlog_set_value(c0, p_cond_predicate());
645✔
2462
   vlog_add_cond(v, c0);
645✔
2463

2464
   consume(tRPAREN);
645✔
2465

2466
   vlog_node_t s0 = p_statement_or_null();
645✔
2467
   if (s0 != NULL)
645✔
2468
      vlog_add_stmt(c0, s0);
634✔
2469

2470
   bool stop = false;
2471
   while (!stop && optional(tELSE)) {
810✔
2472
      vlog_node_t c = vlog_new(V_COND);
165✔
2473
      vlog_add_cond(v, c);
165✔
2474

2475
      if (optional(tIF)) {
165✔
2476
         consume(tLPAREN);
22✔
2477
         vlog_set_value(c, p_cond_predicate());
22✔
2478
         consume(tRPAREN);
22✔
2479
      }
2480
      else
2481
         stop = true;
2482

2483
      vlog_node_t s = p_statement_or_null();
165✔
2484
      if (s != NULL)
165✔
2485
         vlog_add_stmt(c, s);
164✔
2486
   }
2487

2488
   vlog_set_loc(v, CURRENT_LOC);
645✔
2489
   return v;
645✔
2490
}
2491

2492
static vlog_node_t p_variable_assignment(vlog_kind_t kind)
46✔
2493
{
2494
   // variable_lvalue = expression
2495

2496
   BEGIN("variable assignment");
46✔
2497

2498
   vlog_node_t v = vlog_new(kind);
46✔
2499
   vlog_set_target(v, p_variable_lvalue());
46✔
2500

2501
   consume(tEQ);
46✔
2502

2503
   vlog_set_value(v, p_expression());
46✔
2504

2505
   vlog_set_loc(v, CURRENT_LOC);
46✔
2506
   return v;
46✔
2507
}
2508

2509
static void p_list_of_variable_assignments(vlog_node_t parent)
44✔
2510
{
2511
   // variable_assignment { , variable_assignment }
2512

2513
   BEGIN("list of variable assignments");
88✔
2514

2515
   do {
44✔
2516
      vlog_node_t v = p_variable_assignment(V_BASSIGN);
44✔
2517
      vlog_add_stmt(parent, v);
44✔
2518
   } while (optional(tCOMMA));
44✔
2519
}
44✔
2520

2521
static void p_for_variable_declaration(vlog_node_t parent)
2✔
2522
{
2523
   // [ var ] data_type variable_identifier = expression
2524
   //   { , variable_identifier = expression }
2525

2526
   BEGIN("for variable declaration");
4✔
2527

2528
   optional(tVAR);
2✔
2529

2530
   vlog_node_t dt = p_data_type();
2✔
2531

2532
   do {
2✔
2533
      vlog_node_t v = vlog_new(V_VAR_DECL);
2✔
2534
      vlog_set_ident(v, p_identifier());
2✔
2535
      vlog_set_type(v, dt);
2✔
2536

2537
      consume(tEQ);
2✔
2538

2539
      vlog_set_value(v, p_expression());
2✔
2540

2541
      vlog_set_loc(v, CURRENT_LOC);
2✔
2542
      vlog_add_decl(parent, v);
2✔
2543

2544
      vlog_symtab_put(symtab, v);
2✔
2545
   } while (optional(tCOMMA));
2✔
2546
}
2✔
2547

2548
static vlog_node_t p_for_initialization(void)
46✔
2549
{
2550
   // list_of_variable_assignments
2551
   //   | for_variable_declaration { , for_variable_declaration }
2552

2553
   BEGIN("for initialization");
46✔
2554

2555
   vlog_node_t v = vlog_new(V_FOR_INIT);
46✔
2556

2557
   if (scan(tREG, tSTRUCT, tUNION, tENUM, tSVINT, tINTEGER, tSVREAL,
46✔
2558
            tSHORTREAL, tREALTIME, tLOGIC, tVAR)) {
2559
      do {
2✔
2560
         p_for_variable_declaration(v);
2✔
2561
      } while (optional(tCOMMA));
2✔
2562
   }
2563
   else
2564
      p_list_of_variable_assignments(v);
44✔
2565

2566
   vlog_set_loc(v, CURRENT_LOC);
46✔
2567
   return v;
46✔
2568
}
2569

2570
static vlog_node_t p_for_step(void)
46✔
2571
{
2572
   // operator_assignment | inc_or_dec_expression | function_subroutine_call
2573

2574
   BEGIN("for step");
46✔
2575

2576
   vlog_node_t v = vlog_new(V_FOR_STEP);
46✔
2577

2578
   switch (peek()) {
46✔
2579
   case tPLUSPLUS:
1✔
2580
   case tMINUSMINUS:
2581
      vlog_add_stmt(v, p_inc_or_dec_expression(NULL));
1✔
2582
      break;
1✔
2583
   default:
45✔
2584
      {
2585
         vlog_node_t head = p_variable_lvalue();
45✔
2586

2587
         switch (peek()) {
45✔
2588
         case tPLUSPLUS:
14✔
2589
         case tMINUSMINUS:
2590
            vlog_add_stmt(v, p_inc_or_dec_expression(head));
14✔
2591
            break;
14✔
2592
         default:
31✔
2593
            vlog_add_stmt(v, p_operator_assignment(head));
31✔
2594
            break;
31✔
2595
         }
2596
      }
2597
      break;
2598
   }
2599

2600
   vlog_set_loc(v, CURRENT_LOC);
46✔
2601
   return v;
46✔
2602
}
2603

2604
static vlog_node_t p_loop_statement(void)
63✔
2605
{
2606
   // forever statement_or_null
2607
   //   | repeat ( expression ) statement_or_null
2608
   //   | while ( expression ) statement_or_null
2609
   //   | for ( [ for_initialization ] ; [ expression ] ; [ for_step ] )
2610
   //       statement_or_null
2611
   //   | do statement_or_null while ( expression ) ;
2612
   //   | foreach ( ps_or_hierarchical_array_identifier [ loop_variables ] )
2613
   //       statement
2614

2615
   BEGIN("loop statement");
126✔
2616

2617
   switch (one_of(tFOREVER, tWHILE, tREPEAT, tDO, tFOR)) {
63✔
2618
   case tFOREVER:
4✔
2619
      {
2620
         vlog_node_t v = vlog_new(V_FOREVER);
4✔
2621

2622
         vlog_node_t s = p_statement_or_null();
4✔
2623
         if (s != NULL)
4✔
2624
            vlog_add_stmt(v, s);
4✔
2625

2626
         vlog_set_loc(v, CURRENT_LOC);
4✔
2627
         return v;
4✔
2628
      }
2629

2630
   case tWHILE:
5✔
2631
      {
2632
         vlog_node_t v = vlog_new(V_WHILE);
5✔
2633

2634
         consume(tLPAREN);
5✔
2635
         vlog_set_value(v, p_expression());
5✔
2636
         consume(tRPAREN);
5✔
2637

2638
         vlog_node_t s = p_statement_or_null();
5✔
2639
         if (s != NULL)
5✔
2640
            vlog_add_stmt(v, s);
3✔
2641

2642
         vlog_set_loc(v, CURRENT_LOC);
5✔
2643
         return v;
5✔
2644
      }
2645

2646
   case tREPEAT:
5✔
2647
      {
2648
         vlog_node_t v = vlog_new(V_REPEAT);
5✔
2649

2650
         consume(tLPAREN);
5✔
2651
         vlog_set_value(v, p_expression());
5✔
2652
         consume(tRPAREN);
5✔
2653

2654
         vlog_node_t s = p_statement_or_null();
5✔
2655
         if (s != NULL)
5✔
2656
            vlog_add_stmt(v, s);
5✔
2657

2658
         vlog_set_loc(v, CURRENT_LOC);
5✔
2659
         return v;
5✔
2660
      }
2661

2662
   case tDO:
2✔
2663
      {
2664
         vlog_node_t v = vlog_new(V_DO_WHILE);
2✔
2665

2666
         vlog_node_t s = p_statement_or_null();
2✔
2667
         if (s != NULL)
2✔
2668
            vlog_add_stmt(v, s);
2✔
2669

2670
         consume(tWHILE);
2✔
2671

2672
         consume(tLPAREN);
2✔
2673
         vlog_set_value(v, p_expression());
2✔
2674
         consume(tRPAREN);
2✔
2675
         consume(tSEMI);
2✔
2676

2677
         vlog_set_loc(v, CURRENT_LOC);
2✔
2678
         return v;
2✔
2679
      }
2680

2681
   case tFOR:
47✔
2682
      {
2683
         vlog_node_t v = vlog_new(V_FOR_LOOP);
47✔
2684

2685
         vlog_symtab_push(symtab, v);
47✔
2686

2687
         consume(tLPAREN);
47✔
2688

2689
         if (not_at_token(tSEMI))
47✔
2690
            vlog_set_left(v, p_for_initialization());
46✔
2691
         else
2692
            vlog_set_left(v, vlog_new(V_FOR_INIT));
1✔
2693

2694
         consume(tSEMI);
47✔
2695

2696
         if (not_at_token(tSEMI))
47✔
2697
            vlog_set_value(v, p_expression());
45✔
2698

2699
         consume(tSEMI);
47✔
2700

2701
         if (not_at_token(tRPAREN))
47✔
2702
            vlog_set_right(v, p_for_step());
46✔
2703
         else
2704
            vlog_set_right(v, vlog_new(V_FOR_STEP));
1✔
2705

2706
         consume(tRPAREN);
47✔
2707

2708
         vlog_node_t s = p_statement_or_null();
47✔
2709
         if (s != NULL)
47✔
2710
            vlog_add_stmt(v, s);
44✔
2711

2712
         vlog_symtab_pop(symtab);
47✔
2713

2714
         vlog_set_loc(v, CURRENT_LOC);
47✔
2715
         return v;
47✔
2716
      }
2717

UNCOV
2718
   default:
×
2719
      should_not_reach_here();
2720
   }
2721
}
2722

2723
static vlog_node_t p_wait_statement(void)
1✔
2724
{
2725
   // wait ( expression ) statement_or_null
2726
   //   | wait fork ;
2727
   //   | wait_order ( hierarchical_identifier { , hierarchical_identifier } )
2728
   //       action_block
2729

2730
   BEGIN("wait statement");
1✔
2731

2732
   consume(tWAIT);
1✔
2733

2734
   vlog_node_t v = vlog_new(V_WAIT);
1✔
2735

2736
   consume(tLPAREN);
1✔
2737

2738
   vlog_set_value(v, p_expression());
1✔
2739

2740
   consume(tRPAREN);
1✔
2741

2742
   vlog_node_t s = p_statement_or_null();
1✔
2743
   if (s != NULL)
1✔
2744
      vlog_add_stmt(v, s);
1✔
2745

2746
   vlog_set_loc(v, CURRENT_LOC);
1✔
2747
   return v;
1✔
2748
}
2749

2750
static vlog_node_t p_case_item(void)
48✔
2751
{
2752
   // case_item_expression { , case_item_expression } : statement_or_null
2753
   //   | default [ : ] statement_or_null
2754

2755
   BEGIN("case item");
48✔
2756

2757
   vlog_node_t v = vlog_new(V_CASE_ITEM);
48✔
2758

2759
   if (optional(tDEFAULT))
48✔
2760
      optional(tCOLON);
10✔
2761
   else {
2762
      do {
42✔
2763
         vlog_add_param(v, p_expression());
42✔
2764
      } while (optional(tCOMMA));
42✔
2765

2766
      consume(tCOLON);
38✔
2767
   }
2768

2769
   vlog_set_loc(v, CURRENT_LOC);
48✔
2770

2771
   vlog_node_t s = p_statement_or_null();
48✔
2772
   if (s != NULL)
48✔
2773
      vlog_add_stmt(v, s);
47✔
2774

2775
   return v;
48✔
2776
}
2777

2778
static vlog_node_t p_case_statement(void)
12✔
2779
{
2780
   // [ unique_priority ] case_keyword ( case_expression )
2781
   //        case_item { case_item } endcase
2782
   //   | [ unique_priority ] case_keyword ( case_expression ) matches
2783
   //        case_pattern_item { case_pattern_item } endcase
2784
   //   | [ unique_priority ] case ( case_expression ) inside case_inside_item
2785
   //        { case_inside_item } endcase
2786

2787
   BEGIN("case statement");
12✔
2788

2789
   vlog_case_kind_t kind = V_CASE_NORMAL;
12✔
2790
   switch (one_of(tCASE, tCASEX, tCASEZ)) {
12✔
2791
   case tCASEX: kind = V_CASE_X; break;
4✔
UNCOV
2792
   case tCASEZ: kind = V_CASE_Z; break;
×
2793
   }
2794

2795
   vlog_node_t v = vlog_new(V_CASE);
12✔
2796
   vlog_set_subkind(v, kind);
12✔
2797

2798
   consume(tLPAREN);
12✔
2799

2800
   vlog_set_value(v, p_expression());
12✔
2801

2802
   consume(tRPAREN);
12✔
2803

2804
   do {
48✔
2805
      vlog_add_stmt(v, p_case_item());
48✔
2806
   } while (not_at_token(tENDCASE));
48✔
2807

2808
   consume(tENDCASE);
12✔
2809

2810
   vlog_set_loc(v, CURRENT_LOC);
12✔
2811
   return v;
12✔
2812
}
2813

2814
static vlog_node_t p_event_trigger(void)
1✔
2815
{
2816
   // -> hierarchical_event_identifier ;
2817
   //   | ->> [ delay_or_event_control ] hierarchical_event_identifier ;
2818

2819
   BEGIN("event trigger");
1✔
2820

2821
   consume(tIFIMPL);
1✔
2822

2823
   vlog_node_t v = vlog_new(V_EVENT_TRIGGER);
1✔
2824
   vlog_set_ident(v, p_identifier());
1✔
2825

2826
   consume(tSEMI);
1✔
2827

2828
   vlog_set_loc(v, CURRENT_LOC);
1✔
2829
   return v;
1✔
2830
}
2831

2832
static vlog_node_t p_procedural_continuous_assignment(void)
4✔
2833
{
2834
   // assign variable_assignment | deassign variable_lvalue
2835
   //   | force variable_assignment | force net_assignment
2836
   //   | release variable_lvalue | release net_lvalue
2837

2838
   BEGIN("procedural continuous assignment");
8✔
2839

2840
   switch (one_of(tASSIGN, tDEASSIGN, tFORCE, tRELEASE)) {
4✔
2841
   case tASSIGN:
1✔
2842
   default:
2843
      return p_variable_assignment(V_ASSIGN);
1✔
2844
   case tDEASSIGN:
1✔
2845
      {
2846
         vlog_node_t v = vlog_new(V_DEASSIGN);
1✔
2847
         vlog_set_target(v, p_variable_lvalue());
1✔
2848
         vlog_set_loc(v, CURRENT_LOC);
1✔
2849
         return v;
1✔
2850
      }
2851
   case tFORCE:
1✔
2852
      return p_variable_assignment(V_FORCE);
1✔
2853
   case tRELEASE:
1✔
2854
      {
2855
         vlog_node_t v = vlog_new(V_RELEASE);
1✔
2856
         vlog_set_target(v, p_variable_lvalue());
1✔
2857
         vlog_set_loc(v, CURRENT_LOC);
1✔
2858
         return v;
1✔
2859
      }
2860
   }
2861
}
2862

2863
static vlog_node_t p_disable_statement(void)
1✔
2864
{
2865
   // disable hierarchical_task_identifier ;
2866
   //   | disable hierarchical_block_identifier ;
2867
   //   | disable fork ;
2868

2869
   BEGIN("disable statement");
1✔
2870

2871
   consume(tDISABLE);
1✔
2872

2873
   vlog_node_t v = vlog_new(V_DISABLE);
1✔
2874
   vlog_set_ident(v, p_identifier());
1✔
2875

2876
   consume(tSEMI);
1✔
2877

2878
   vlog_set_loc(v, CURRENT_LOC);
1✔
2879
   return v;
1✔
2880
}
2881

2882
static vlog_node_t p_jump_statement(void)
6✔
2883
{
2884
   // return [ expression ] ; | break ; | continue ;
2885

2886
   BEGIN("jump statement");
6✔
2887

2888
   switch (one_of(tRETURN)) {
6✔
2889
   case tRETURN:
6✔
2890
      {
2891
         vlog_node_t v = vlog_new(V_RETURN);
6✔
2892

2893
         vlog_node_t subr = vlog_symtab_subr(symtab);
6✔
2894
         if (subr == NULL)
6✔
2895
            parse_error(&state.last_loc, "return statement can only be used "
1✔
2896
                        "in a subroutine");
2897
         else
2898
            vlog_set_ref(v, subr);
5✔
2899

2900
         if (peek() != tSEMI)
6✔
2901
            vlog_set_value(v, p_expression());
4✔
2902

2903
         consume(tSEMI);
6✔
2904

2905
         vlog_set_loc(v, CURRENT_LOC);
6✔
2906
         return v;
12✔
2907
      }
UNCOV
2908
   default:
×
2909
      should_not_reach_here();
2910
   }
2911
}
2912

2913
static vlog_node_t p_statement_item(ident_t id)
5,586✔
2914
{
2915
   // blocking_assignment ; | nonblocking_assignment ;
2916
   //   | procedural_continuous_assignment ; | case_statement
2917
   //   | conditional_statement | inc_or_dec_expression ;
2918
   //   | subroutine_call_statement | disable_statement
2919
   //   | event_trigger | loop_statement | jump_statement
2920
   //   | par_block | procedural_timing_control_statement
2921
   //   | seq_block | wait_statement | procedural_assertion_statement
2922
   //   | clocking_drive ; | randsequence_statement | randcase_statement
2923
   //   | expect_property_statement
2924

2925
   BEGIN("statement item");
11,172✔
2926

2927
   switch (peek()) {
5,586✔
2928
   case tID:
1,869✔
2929
      switch (peek_nth(2)) {
1,869✔
2930
      case tLPAREN:
10✔
2931
      case tSEMI:
2932
      case tATTRBEGIN:
2933
         return p_subroutine_call_statement();
10✔
2934
      default:
1,859✔
2935
         {
2936
            vlog_node_t lhs = p_variable_lvalue(), v;
1,859✔
2937

2938
            switch (peek()) {
1,859✔
2939
            case tLE:
144✔
2940
               v = p_nonblocking_assignment(lhs);
144✔
2941
               break;
144✔
2942
            case tPLUSPLUS:
3✔
2943
            case tMINUSMINUS:
2944
               v = p_inc_or_dec_expression(lhs);
3✔
2945
               break;
3✔
2946
            default:
1,712✔
2947
               v = p_blocking_assignment(lhs);
1,712✔
2948
               break;
1,712✔
2949
            }
2950

2951
            consume(tSEMI);
1,859✔
2952
            return v;
1,859✔
2953
         }
2954
      }
2955
   case tLBRACE:
4✔
2956
      {
2957
         vlog_node_t lhs = p_variable_lvalue(), v;
4✔
2958

2959
         if (peek() == tLE)
4✔
UNCOV
2960
            v = p_nonblocking_assignment(lhs);
×
2961
         else
2962
            v = p_blocking_assignment(lhs);
4✔
2963

2964
         consume(tSEMI);
4✔
2965
         return v;
4✔
2966
      }
2967
   case tDISABLE:
1✔
2968
      return p_disable_statement();
1✔
2969
   case tAT:
784✔
2970
   case tHASH:
2971
      return p_procedural_timing_control_statement();
784✔
2972
   case tBEGIN:
795✔
2973
      return p_seq_block(id);
795✔
2974
   case tFORK:
7✔
2975
      return p_par_block(id);
7✔
2976
   case tSYSTASK:
1,392✔
2977
   case tVOID:
2978
      return p_subroutine_call_statement();
1,392✔
2979
   case tIF:
645✔
2980
      return p_conditional_statement();
645✔
2981
   case tFOREVER:
63✔
2982
   case tWHILE:
2983
   case tREPEAT:
2984
   case tDO:
2985
   case tFOR:
2986
      return p_loop_statement();
63✔
2987
   case tWAIT:
1✔
2988
      return p_wait_statement();
1✔
2989
   case tCASE:
12✔
2990
   case tCASEX:
2991
   case tCASEZ:
2992
      return p_case_statement();
12✔
2993
   case tIFIMPL:
1✔
2994
      return p_event_trigger();
1✔
2995
   case tASSIGN:
4✔
2996
   case tDEASSIGN:
2997
   case tFORCE:
2998
   case tRELEASE:
2999
      {
3000
         vlog_node_t v = p_procedural_continuous_assignment();
4✔
3001
         consume(tSEMI);
4✔
3002
         return v;
4✔
3003
      }
3004
   case tRETURN:
6✔
3005
      return p_jump_statement();
6✔
3006
   default:
2✔
3007
      one_of(tID, tAT, tHASH, tBEGIN, tFORK, tSYSTASK, tVOID, tIF, tFOREVER,
2✔
3008
             tWHILE, tREPEAT, tDO, tFOR, tWAIT, tCASE, tCASEX, tCASEZ, tIFIMPL,
3009
             tASSIGN, tDEASSIGN, tFORCE, tRELEASE, tRETURN);
3010
      drop_tokens_until(tSEMI);
2✔
3011
      return vlog_new(V_BLOCK);  // Dummy statement
2✔
3012
   }
3013
}
3014

3015
static vlog_node_t p_statement(void)
5,586✔
3016
{
3017
   // [ block_identifier : ] { attribute_instance } statement_item
3018

3019
   BEGIN("statement");
11,172✔
3020

3021
   ident_t id = NULL;
5,586✔
3022
   if (peek() == tID && peek_nth(2) == tCOLON) {
5,586✔
3023
      id = p_identifier();
6✔
3024
      consume(tCOLON);
6✔
3025
   }
3026

3027
   optional_attributes();
5,586✔
3028

3029
   return p_statement_item(id);
5,586✔
3030
}
3031

3032
static vlog_node_t p_statement_or_null(void)
5,927✔
3033
{
3034
   // statement | { attribute_instance } ;
3035

3036
   BEGIN("statement or null");
11,854✔
3037

3038
   if (optional(tSEMI))
5,927✔
3039
      return NULL;
3040
   else
3041
      return p_statement();
5,423✔
3042
}
3043

3044
static vlog_node_t p_always_construct(void)
163✔
3045
{
3046
   // always_keyword statement
3047

3048
   BEGIN("always construct");
163✔
3049

3050
   vlog_node_t v = vlog_new(V_ALWAYS);
163✔
3051

3052
   switch (one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH)) {
163✔
3053
   case tALWAYSCOMB:  vlog_set_subkind(v, V_ALWAYS_COMB);  break;
1✔
3054
   case tALWAYSFF:    vlog_set_subkind(v, V_ALWAYS_FF);    break;
1✔
3055
   case tALWAYSLATCH: vlog_set_subkind(v, V_ALWAYS_LATCH); break;
4✔
3056
   default:           vlog_set_subkind(v, V_ALWAYS_PLAIN); break;
157✔
3057
   }
3058

3059
   vlog_set_ident(v, default_label("always"));
163✔
3060
   vlog_add_stmt(v, p_statement());
163✔
3061

3062
   vlog_set_loc(v, CURRENT_LOC);
163✔
3063
   return v;
163✔
3064
}
3065

3066
static vlog_node_t p_initial_construct(void)
325✔
3067
{
3068
   // initial statement_or_null
3069

3070
   BEGIN("initial construct");
325✔
3071

3072
   consume(tINITIAL);
325✔
3073

3074
   vlog_node_t v = vlog_new(V_INITIAL);
325✔
3075
   vlog_set_ident(v, default_label("initial"));
325✔
3076

3077
   vlog_node_t s = p_statement_or_null();
325✔
3078
   if (s != NULL)
325✔
3079
      vlog_add_stmt(v, s);
325✔
3080

3081
   vlog_set_loc(v, CURRENT_LOC);
325✔
3082
   return v;
325✔
3083
}
3084

3085
static vlog_node_t p_net_assignment(vlog_node_t delay)
246✔
3086
{
3087
   // net_lvalue = expression
3088

3089
   BEGIN("net assignment");
246✔
3090

3091
   vlog_symtab_set_implicit(symtab, implicit_kind);
246✔
3092

3093
   vlog_node_t v = vlog_new(V_ASSIGN);
246✔
3094
   vlog_set_target(v, p_net_lvalue());
246✔
3095
   vlog_set_ident(v, default_label("assign"));
246✔
3096
   vlog_set_delay(v, delay);
246✔
3097

3098
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
246✔
3099

3100
   consume(tEQ);
246✔
3101

3102
   vlog_set_value(v, p_expression());
246✔
3103

3104
   vlog_set_loc(v, CURRENT_LOC);
246✔
3105
   return v;
246✔
3106
}
3107

3108
static void p_list_of_net_assignments(vlog_node_t mod, vlog_node_t delay)
246✔
3109
{
3110
   // net_assignment { , net_assignment }
3111

3112
   BEGIN("list of net assignments");
492✔
3113

3114
   do {
246✔
3115
      vlog_add_stmt(mod, p_net_assignment(delay));
246✔
3116
   } while (optional(tCOMMA));
246✔
3117
}
246✔
3118

3119
static void p_continuous_assign(vlog_node_t mod)
246✔
3120
{
3121
   // assign [ drive_strength ] [ delay3 ] list_of_net_assignments ;
3122
   //   | assign [ delay_control ] list_of_variable_assignments ;
3123

3124
   BEGIN("continuous assignment");
492✔
3125

3126
   consume(tASSIGN);
246✔
3127

3128
   vlog_node_t delay = NULL;
246✔
3129
   if (peek() == tLPAREN) {
246✔
3130
      p_drive_strength();
3✔
3131
      if (peek() == tHASH)
3✔
3132
         p_delay3();
2✔
3133
   } else if (peek() == tHASH)
243✔
3134
      delay = p_delay_control();
6✔
3135

3136
   p_list_of_net_assignments(mod, delay);
246✔
3137

3138
   consume(tSEMI);
246✔
3139
}
246✔
3140

3141
static vlog_net_kind_t p_net_type(void)
306✔
3142
{
3143
   // supply0 | supply1 | tri | triand | trior | trireg | tri0
3144
   //   | tri1 | uwire | wire | wand | wor
3145

3146
   BEGIN("net type");
612✔
3147

3148
   switch (one_of(tWIRE, tUWIRE, tSUPPLY0, tSUPPLY1, tTRI, tTRIAND,
306✔
3149
                  tTRIOR, tTRIREG, tTRI0, tTRI1, tWAND, tWOR)) {
3150
   case tSUPPLY0: return V_NET_SUPPLY0;
3151
   case tSUPPLY1: return V_NET_SUPPLY1;
3✔
3152
   case tTRI:     return V_NET_TRI;
1✔
3153
   case tTRIAND:  return V_NET_TRIAND;
2✔
3154
   case tTRIOR:   return V_NET_TRIOR;
2✔
3155
   case tTRIREG:  return V_NET_TRIREG;
1✔
3156
   case tTRI0:    return V_NET_TRI0;
4✔
3157
   case tTRI1:    return V_NET_TRI1;
2✔
3158
   case tUWIRE:   return V_NET_UWIRE;
1✔
3159
   case tWAND:    return V_NET_WAND;
1✔
3160
   case tWOR:     return V_NET_WOR;
1✔
3161
   case tWIRE:
282✔
3162
   default:       return V_NET_WIRE;
282✔
3163
   }
3164
}
3165

3166
static vlog_node_t p_net_decl_assignment(vlog_net_kind_t kind,
293✔
3167
                                         vlog_node_t datatype)
3168
{
3169
   // net_identifier { unpacked_dimension } [ = expression ]
3170

3171
   BEGIN("net declaration assignment");
293✔
3172

3173
   vlog_node_t v = vlog_new(V_NET_DECL);
293✔
3174
   vlog_set_subkind(v, kind);
293✔
3175
   vlog_set_type(v, datatype);
293✔
3176
   vlog_set_ident(v, p_identifier());
293✔
3177

3178
   while (peek() == tLSQUARE)
298✔
3179
      vlog_add_range(v, p_unpacked_dimension());
5✔
3180

3181
   if (optional(tEQ))
293✔
3182
      vlog_set_value(v, p_expression());
36✔
3183

3184
   vlog_set_loc(v, CURRENT_LOC);
293✔
3185
   vlog_symtab_put(symtab, v);
293✔
3186
   return v;
293✔
3187
}
3188

3189
static void p_list_of_net_decl_assignments(vlog_node_t mod,
253✔
3190
                                           vlog_net_kind_t kind,
3191
                                           vlog_node_t datatype)
3192
{
3193
   // net_decl_assignment { , net_decl_assignment }
3194

3195
   BEGIN("list of net declaration assignments");
506✔
3196

3197
   do {
293✔
3198
      vlog_node_t v = p_net_decl_assignment(kind, datatype);
293✔
3199
      vlog_add_decl(mod, v);
293✔
3200
   } while (optional(tCOMMA));
293✔
3201
}
253✔
3202

3203
static vlog_node_t p_drive_strength(void)
7✔
3204
{
3205
   //( strength0 , strength1 ) | ( strength1 , strength0 )
3206
   //| ( strength0 , highz1 )  | ( strength1 , highz0 )
3207
   //| ( highz0 , strength1 )  | ( highz1 , strength0 )
3208

3209
   BEGIN("drive strength");
7✔
3210

3211
   consume(tLPAREN);
7✔
3212

3213
   vlog_strength_t s0, s1;
7✔
3214
   switch (peek()) {
7✔
3215
   case tSUPPLY0:
5✔
3216
   case tSTRONG0:
3217
   case tPULL0:
3218
   case tWEAK0:
3219
      {
3220
         s0 = p_strength0();
5✔
3221
         consume(tCOMMA);
5✔
3222
         if (optional(tHIGHZ1))
5✔
3223
            s1 = V_STRENGTH_HIGHZ;
3224
         else
3225
            s1 = p_strength1();
4✔
3226
      }
3227
      break;
3228
   case tHIGHZ0:
1✔
3229
      {
3230
         s0 = V_STRENGTH_HIGHZ;
1✔
3231
         consume(tHIGHZ0);
1✔
3232
         consume(tCOMMA);
1✔
3233
         s1 = p_strength1();
1✔
3234
      }
3235
      break;
1✔
3236
   case tSUPPLY1:
×
3237
   case tSTRONG1:
3238
   case tPULL1:
3239
   case tWEAK1:
3240
      {
UNCOV
3241
         s1 = p_strength1();
×
UNCOV
3242
         consume(tCOMMA);
×
UNCOV
3243
         if (optional(tHIGHZ0))
×
3244
            s0 = V_STRENGTH_HIGHZ;
3245
         else
UNCOV
3246
            s0 = p_strength0();
×
3247
      }
3248
      break;
3249
   case tHIGHZ1:
1✔
3250
      {
3251
         s1 = V_STRENGTH_HIGHZ;
1✔
3252
         consume(tHIGHZ1);
1✔
3253
         consume(tCOMMA);
1✔
3254
         s0 = p_strength0();
1✔
3255
      }
3256
      break;
1✔
UNCOV
3257
   default:
×
3258
      should_not_reach_here();
3259
   }
3260

3261
   consume(tRPAREN);
7✔
3262

3263
   vlog_node_t v = vlog_new(V_STRENGTH);
7✔
3264
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
7✔
3265
   vlog_set_loc(v, CURRENT_LOC);
7✔
3266

3267
   return v;
7✔
3268
}
3269

3270
static vlog_strength_t p_charge_strength(void)
2✔
3271
{
3272
   // ( small ) | ( medium ) | ( large )
3273

3274
   BEGIN("drive charge");
2✔
3275

3276
   consume(tLPAREN);
2✔
3277

3278
   vlog_strength_t s;
2✔
3279
   switch (one_of(tSMALL, tMEDIUM, tLARGE)) {
2✔
3280
   default:
3281
   case tSMALL:  s = V_STRENGTH_SMALL;
3282
   case tMEDIUM: s = V_STRENGTH_MEDIUM;
2✔
3283
   case tLARGE:  s = V_STRENGTH_LARGE;
2✔
3284
   }
3285

3286
   consume(tRPAREN);
2✔
3287

3288
   return s;
2✔
3289
}
3290

3291
static void p_net_declaration(vlog_node_t mod)
254✔
3292
{
3293
   // net_type [ drive_strength | charge_strength ] [ vectored | scalared ]
3294
   //     data_type_or_implicit [ delay3 ] list_of_net_decl_assignments ;
3295
   //  | net_type_identifier [ delay_control ] list_of_net_decl_assignments ;
3296
   //  | interconnect implicit_data_type [ # delay_value ] net_identifier
3297
   //     { unpacked_dimension } [ , net_identifier { unpacked_dimension } ] ;
3298

3299
   BEGIN("net declaration");
508✔
3300

3301
   ident_t id;
254✔
3302
   vlog_node_t dt;
254✔
3303
   vlog_net_kind_t kind = V_NET_WIRE;
254✔
3304

3305
   switch (peek()) {
254✔
3306
   case tINTERCONNECT:
1✔
3307
      {
3308
         consume(tINTERCONNECT);
1✔
3309

3310
         dt = p_implicit_data_type();
1✔
3311

3312
         if (optional(tHASH))
1✔
3313
            p_delay_value();
1✔
3314

3315
         do {
1✔
3316
            id = p_identifier();
1✔
3317
            if (peek() == tLSQUARE)
1✔
3318
               p_unpacked_dimension();
1✔
3319
         } while (optional(tCOMMA));
1✔
3320
      }
3321
      break;
3322

UNCOV
3323
   case tID:
×
3324
      {
UNCOV
3325
         id = p_identifier();
×
3326
         dt = vlog_symtab_query(symtab, id);
×
3327
         if (dt == NULL)
×
3328
            should_not_reach_here();
3329
         // TODO check that the identifier is actually
3330
         // a user declared nettype
3331

UNCOV
3332
         if (peek() == tHASH)
×
UNCOV
3333
            p_delay_control();
×
3334

UNCOV
3335
         p_list_of_net_decl_assignments(mod, kind, dt);
×
3336
      }
UNCOV
3337
      break;
×
3338

3339
   default:
253✔
3340
      {
3341
         kind = p_net_type();
253✔
3342

3343
         if (peek() == tLPAREN) {
253✔
3344
            switch (peek_nth(2)) {
4✔
3345
            case tHIGHZ0:
2✔
3346
            case tHIGHZ1:
3347
            case tSUPPLY0:
3348
            case tSUPPLY1:
3349
            case tSTRONG0:
3350
            case tSTRONG1:
3351
            case tPULL0:
3352
            case tPULL1:
3353
            case tWEAK0:
3354
            case tWEAK1:
3355
               p_drive_strength();
2✔
3356
               break;
2✔
3357
            case tSMALL:
2✔
3358
            case tMEDIUM:
3359
            case tLARGE:
3360
               if (kind != V_NET_TRIREG)
2✔
3361
                  parse_error(&state.last_loc, "charge strength only allowed "
1✔
3362
                              "with the trireg keyword");
3363
               p_charge_strength();
2✔
3364
               break;
2✔
UNCOV
3365
            default:
×
UNCOV
3366
               one_of(tHIGHZ0, tHIGHZ1, tSUPPLY0, tSUPPLY1, tSTRONG0, tSTRONG1,
×
3367
                     tPULL0, tPULL1, tWEAK0, tWEAK1, tSMALL, tMEDIUM, tLARGE);
UNCOV
3368
               drop_tokens_until(tSEMI);
×
UNCOV
3369
               return;
×
3370
            }
3371
         }
3372

3373
         bool need_packed = false;
253✔
3374
         if (optional(tVECTORED) || optional(tSCALARED))
253✔
3375
            need_packed = true;
3376

3377
         dt = p_data_type_or_implicit();
253✔
3378

3379
         if (need_packed) {
253✔
3380
            bool has_packed = false;
2✔
3381
            unsigned ranges = vlog_ranges(dt);
2✔
3382
            for (unsigned i = 0; i < ranges; i++) {
3✔
3383
               vlog_node_t r = vlog_range(dt, i);
1✔
3384
               if (vlog_subkind(r) == V_DIM_PACKED)
1✔
3385
                  has_packed |= true;
1✔
3386
            }
3387
            if (!has_packed)
2✔
3388
               parse_error(&state.last_loc, "vectored and scalared keywords "
1✔
3389
                           "are only allowed with at least a packed dimension");
3390
         }
3391

3392
         if (peek() == tHASH)
253✔
3393
            p_delay3();
5✔
3394

3395
         p_list_of_net_decl_assignments(mod, kind, dt);
253✔
3396
      }
3397
   }
3398

3399
   consume(tSEMI);
254✔
3400
}
3401

3402
static vlog_node_t p_unsized_dimension(void)
1✔
3403
{
3404
   // [ ]
3405

3406
   BEGIN("unsized dimension");
1✔
3407

3408
   consume(tLSQUARE);
1✔
3409
   consume(tRSQUARE);
1✔
3410

3411
   vlog_node_t v = vlog_new(V_DIMENSION);
1✔
3412
   vlog_set_subkind(v, V_DIM_UNSIZED);
1✔
3413
   vlog_set_loc(v, CURRENT_LOC);
1✔
3414

3415
   return v;
1✔
3416
}
3417

3418
static vlog_node_t p_variable_dimension(void)
21✔
3419
{
3420
   // unsized_dimension | unpacked_dimension | associative_dimension
3421
   //   | queue_dimension
3422

3423
   BEGIN("variable dimension");
42✔
3424

3425
   switch (peek_nth(2)) {
21✔
3426
   case tRSQUARE:
1✔
3427
      return p_unsized_dimension();
1✔
3428
   default:
20✔
3429
      return p_unpacked_dimension();
20✔
3430
   }
3431
}
3432

3433
static vlog_node_t p_variable_decl_assignment(vlog_node_t datatype)
820✔
3434
{
3435
   // variable_identifier { variable_dimension } [ = expression ]
3436
   //   | dynamic_array_variable_identifier unsized_dimension
3437
   //       { variable_dimension } [ = dynamic_array_new ]
3438
   //   | class_variable_identifier [ = class_new ]
3439

3440
   BEGIN("variable declaration assignment");
820✔
3441

3442
   vlog_node_t v = vlog_new(V_VAR_DECL);
820✔
3443
   vlog_set_ident(v, p_identifier());
820✔
3444
   vlog_set_type(v, datatype);
820✔
3445

3446
   while (peek() == tLSQUARE)
841✔
3447
      vlog_add_range(v, p_variable_dimension());
21✔
3448

3449
   if (optional(tEQ))
820✔
3450
      vlog_set_value(v, p_expression());
77✔
3451

3452
   vlog_set_loc(v, CURRENT_LOC);
820✔
3453
   vlog_symtab_put(symtab, v);
820✔
3454
   return v;
820✔
3455
}
3456

3457
static void p_list_of_variable_decl_assignments(vlog_node_t parent,
611✔
3458
                                                vlog_node_t datatype)
3459
{
3460
   // variable_decl_assignment { , variable_decl_assignment }
3461

3462
   BEGIN("list of variable declaration assignments");
1,222✔
3463

3464
   do {
820✔
3465
      vlog_add_decl(parent, p_variable_decl_assignment(datatype));
820✔
3466
   } while (optional(tCOMMA));
820✔
3467
}
611✔
3468

3469
static vlog_node_t p_type_declaration(void)
11✔
3470
{
3471
   // typedef data_type type_identifier { variable_dimension } ;
3472
   //   | typedef interface_instance_identifier constant_bit_select .
3473
   //       type_identifier type_identifier ;
3474
   //   | typedef [ enum | struct | union | class | interface class ]
3475
   //       type_identifier ;
3476

3477
   BEGIN("type declaration");
11✔
3478

3479
   consume(tTYPEDEF);
11✔
3480

3481
   vlog_node_t v = vlog_new(V_TYPE_DECL);
11✔
3482
   vlog_set_type(v, p_data_type());
11✔
3483
   vlog_set_ident(v, p_identifier());
11✔
3484

3485
   consume(tSEMI);
11✔
3486

3487
   vlog_set_loc(v, CURRENT_LOC);
11✔
3488
   vlog_symtab_put(symtab, v);
11✔
3489
   return v;
11✔
3490
}
3491

3492
static vlog_node_t p_package_import_item(void)
1✔
3493
{
3494
   // package_identifier :: identifier | package_identifier :: *
3495

3496
   BEGIN("package import item");
1✔
3497

3498
   vlog_node_t v = vlog_new(V_IMPORT_DECL);
1✔
3499
   vlog_set_ident(v, p_identifier());
1✔
3500

3501
   consume(tSCOPE);
1✔
3502

3503
   if (peek() == tID)
1✔
UNCOV
3504
      vlog_set_ident2(v, p_identifier());
×
3505
   else
3506
      one_of(tTIMES, tID);
1✔
3507

3508
   vlog_set_loc(v, CURRENT_LOC);
1✔
3509
   return v;
1✔
3510
}
3511

3512
static void p_package_import_declaration(vlog_node_t parent)
1✔
3513
{
3514
   // import package_import_item { , package_import_item } ;
3515

3516
   BEGIN("package import declaration");
2✔
3517

3518
   consume(tIMPORT);
1✔
3519

3520
   do {
1✔
3521
      vlog_add_decl(parent, p_package_import_item());
1✔
3522
   } while (optional(tCOMMA));
1✔
3523

3524
   consume(tSEMI);
1✔
3525
}
1✔
3526

3527
static void p_data_declaration(vlog_node_t mod)
611✔
3528
{
3529
   // [ const ] [ var ] [ lifetime ] data_type_or_implicit
3530
   //     list_of_variable_decl_assignments ;
3531
   //  | type_declaration | package_import_declaration | net_type_declaration
3532

3533
   BEGIN("data declaration");
1,222✔
3534

3535
   switch (peek()) {
611✔
3536
   case tTYPEDEF:
11✔
3537
      vlog_add_decl(mod, p_type_declaration());
11✔
3538
      break;
11✔
3539
   case tIMPORT:
1✔
3540
      p_package_import_declaration(mod);
1✔
3541
      break;
1✔
3542
   default:
599✔
3543
      {
3544
         optional(tVAR);
599✔
3545

3546
         vlog_node_t dt = p_data_type_or_implicit();
599✔
3547
         p_list_of_variable_decl_assignments(mod, dt);
599✔
3548

3549
         consume(tSEMI);
599✔
3550
      }
3551
   }
3552
}
611✔
3553

3554
static v_port_kind_t p_port_direction(void)
50✔
3555
{
3556
   // input | output | inout | ref
3557

3558
   BEGIN("port direction");
100✔
3559

3560
   switch (one_of(tINPUT, tOUTPUT, tINOUT)) {
50✔
3561
   case tINPUT:  return V_PORT_INPUT;
3562
   case tOUTPUT: return V_PORT_OUTPUT;
4✔
3563
   case tINOUT:  return V_PORT_INOUT;
1✔
3564
   default:      return V_PORT_INPUT;
3565
   }
3566
}
3567

3568
static v_port_kind_t p_tf_port_direction(void)
50✔
3569
{
3570
   // port_direction | const ref
3571

3572
   BEGIN("task or function port direction");
100✔
3573

3574
   return p_port_direction();
50✔
3575
}
3576

3577
static vlog_node_t p_tf_port_item(void)
27✔
3578
{
3579
   // { attribute_instance } [ tf_port_direction ] [ var ]
3580
   //    data_type_or_implicit [ port_identifier { variable_dimension }
3581
   //    [ = expression ] ]
3582

3583
   BEGIN("task or function port item");
27✔
3584

3585
   vlog_node_t v = vlog_new(V_TF_PORT_DECL);
27✔
3586

3587
   skip_over_attributes();
27✔
3588

3589
   if (scan(tINPUT, tOUTPUT, tINOUT))
27✔
3590
      vlog_set_subkind(v, p_tf_port_direction());
18✔
3591
   else
3592
      vlog_set_subkind(v, V_PORT_INPUT);
9✔
3593

3594
   vlog_set_type(v, p_data_type_or_implicit());
27✔
3595

3596
   if (peek() == tID) {
27✔
3597
      vlog_set_ident(v, p_identifier());
26✔
3598

3599
      if (optional(tEQ))
26✔
3600
         vlog_set_value(v, p_expression());
2✔
3601
   }
3602

3603
   vlog_set_loc(v, CURRENT_LOC);
27✔
3604
   return v;
27✔
3605
}
3606

3607
static void p_tf_port_list(vlog_node_t tf)
16✔
3608
{
3609
   // tf_port_item { , tf_port_item }
3610

3611
   BEGIN("task or function port list");
32✔
3612

3613
   do {
25✔
3614
      vlog_node_t v = p_tf_port_item();
25✔
3615
      vlog_add_port(tf, v);
25✔
3616

3617
      if (vlog_has_ident(v))  // Ignore unnamed ports
25✔
3618
         vlog_symtab_put(symtab, v);
24✔
3619
   } while (optional(tCOMMA));
25✔
3620
}
16✔
3621

3622
static void p_list_of_tf_variable_identifiers(vlog_node_t tf,
32✔
3623
                                              v_port_kind_t kind,
3624
                                              vlog_node_t dt)
3625
{
3626
   // port_identifier { variable_dimension } [ = expression ]
3627
   //    { , port_identifier { variable_dimension } [ = expression ] }
3628

3629
   BEGIN("list of task or function variable identifiers");
64✔
3630

3631
   do {
37✔
3632
      vlog_node_t v = vlog_new(V_TF_PORT_DECL);
37✔
3633
      vlog_set_subkind(v, kind);
37✔
3634
      vlog_set_type(v, dt);
37✔
3635
      vlog_set_ident(v, p_identifier());
37✔
3636
      vlog_set_loc(v, &state.last_loc);
37✔
3637

3638
      if (optional(tEQ))
37✔
3639
         vlog_set_value(v, p_expression());
1✔
3640

3641
      vlog_add_port(tf, v);
37✔
3642
      vlog_symtab_put(symtab, v);
37✔
3643
   } while (optional(tCOMMA));
37✔
3644
}
32✔
3645

3646
static void p_tf_port_declaration(vlog_node_t tf)
32✔
3647
{
3648
   // { attribute_instance } tf_port_direction [ var ] data_type_or_implicit
3649
   //    list_of_tf_variable_identifiers ;
3650

3651
   BEGIN("task or function port declaration");
64✔
3652

3653
   v_port_kind_t kind = p_tf_port_direction();
32✔
3654

3655
   optional(tVAR);
32✔
3656

3657
   vlog_node_t dt = p_data_type_or_implicit();
32✔
3658

3659
   p_list_of_tf_variable_identifiers(tf, kind, dt);
32✔
3660

3661
   consume(tSEMI);
32✔
3662
}
32✔
3663

3664
static void p_tf_item_declaration(vlog_node_t tf)
42✔
3665
{
3666
   // block_item_declaration | tf_port_declaration
3667

3668
   BEGIN("task or function item declaration");
84✔
3669

3670
   switch (peek()) {
42✔
3671
   case tINPUT:
32✔
3672
   case tOUTPUT:
3673
   case tCONST:
3674
      p_tf_port_declaration(tf);
32✔
3675
      break;
32✔
3676
   default:
10✔
3677
      p_block_item_declaration(tf);
10✔
3678
      break;
10✔
3679
   }
3680
}
42✔
3681

3682
static void p_task_body_declaration(vlog_node_t task)
14✔
3683
{
3684
   // [ interface_identifier . | class_scope ] task_identifier ;
3685
   //    { tf_item_declaration } { statement_or_null }
3686
   //    endtask [ : task_identifier ]
3687
   // | [ interface_identifier . | class_scope ] task_identifier
3688
   //    ( [ tf_port_list ] ) ; { block_item_declaration }
3689
   //    { statement_or_null } endtask [ : task_identifier ]
3690

3691
   BEGIN("task body declaration");
28✔
3692

3693
   ident_t id = p_identifier();
14✔
3694
   vlog_set_ident(task, id);
14✔
3695
   vlog_set_loc(task, &state.last_loc);
14✔
3696

3697
   vlog_symtab_put(symtab, task);
14✔
3698

3699
   vlog_symtab_push(symtab, task);
14✔
3700

3701
   if (optional(tLPAREN)) {
14✔
3702
      if (peek() != tRPAREN)
6✔
3703
         p_tf_port_list(task);
6✔
3704
      consume(tRPAREN);
6✔
3705

3706
      consume(tSEMI);
6✔
3707

3708
      skip_over_attributes();
6✔
3709

3710
      while (scan_block_item_declaration()) {
6✔
UNCOV
3711
         p_block_item_declaration(task);
×
UNCOV
3712
         skip_over_attributes();
×
3713
      }
3714
   }
3715
   else {
3716
      consume(tSEMI);
8✔
3717

3718
      skip_over_attributes();
8✔
3719

3720
      while (scan_tf_item_declaration()) {
19✔
3721
         p_tf_item_declaration(task);
11✔
3722
         skip_over_attributes();
11✔
3723
      }
3724
   }
3725

3726
   while (not_at_token(tENDTASK)) {
27✔
3727
      vlog_node_t s = p_statement_or_null();
13✔
3728
      if (s != NULL)
13✔
3729
         vlog_add_stmt(task, s);
13✔
3730
   }
3731

3732
   consume(tENDTASK);
14✔
3733

3734
   if (optional(tCOLON)) {
14✔
3735
      ident_t name = p_identifier();
2✔
3736
      if (id != name)
2✔
3737
         error_at(&state.last_loc, "'%s' does not match task name '%s'",
1✔
3738
                  istr(name), istr(id));
3739
   }
3740

3741
   vlog_symtab_pop(symtab);
14✔
3742
}
14✔
3743

3744
static void p_lifetime(void)
1✔
3745
{
3746
   // static | automatic
3747

3748
   BEGIN("lifetime");
2✔
3749

3750
   one_of(tAUTOMATIC);
1✔
3751
}
1✔
3752

3753
static vlog_node_t p_task_declaration(void)
14✔
3754
{
3755
   // task [ dynamic_override_specifiers ] [ lifetime ] task_body_declaration
3756

3757
   BEGIN("task declaration");
14✔
3758

3759
   vlog_node_t v = vlog_new(V_TASK_DECL);
14✔
3760

3761
   consume(tTASK);
14✔
3762

3763
   if (scan(tAUTOMATIC))
14✔
UNCOV
3764
      p_lifetime();
×
3765

3766
   p_task_body_declaration(v);
14✔
3767

3768
   vlog_set_loc(v, CURRENT_LOC);
14✔
3769
   return v;
14✔
3770
}
3771

3772
static vlog_node_t p_function_data_type_or_implicit(void)
38✔
3773
{
3774
   // data_type_or_void | implicit_data_type
3775

3776
   BEGIN("function data type or implicit");
76✔
3777

3778
   switch (peek()) {
38✔
3779
   case tREG:
9✔
3780
   case tSTRUCT:
3781
   case tUNION:
3782
   case tENUM:
3783
   case tSVINT:
3784
   case tINTEGER:
3785
   case tSVREAL:
3786
   case tSHORTREAL:
3787
   case tREALTIME:
3788
   case tLOGIC:
3789
   case tBIT:
3790
   case tSHORTINT:
3791
   case tSTRINGK:
3792
   case tEVENT:
3793
   case tVOID:
3794
      return p_data_type_or_void();
9✔
3795
   case tID:
8✔
3796
      {
3797
         vlog_node_t dt = peek_reference();
8✔
3798
         if (dt != NULL && is_data_type(dt)) {
8✔
3799
            consume(tID);
1✔
3800
            return dt;
1✔
3801
         }
3802
         else
3803
            return p_implicit_data_type();
7✔
3804
      }
3805
   default:
21✔
3806
      return p_implicit_data_type();
21✔
3807
   }
3808
}
3809

3810
static void p_function_body_declaration(vlog_node_t func)
38✔
3811
{
3812
   // function_data_type_or_implicit [ interface_identifier . | class_scope ]
3813
   //    function_identifier ; { tf_item_declaration }
3814
   //    { function_statement_or_null } endfunction [ : function_identifier ]
3815
   // | function_data_type_or_implicit [ interface_identifier . | class_scope ]
3816
   //    function_identifier ( [ tf_port_list ] ) ; { block_item_declaration }
3817
   //    { function_statement_or_null } endfunction [ : function_identifier ]
3818

3819
   BEGIN("function body declaration");
76✔
3820

3821
   vlog_set_type(func, p_function_data_type_or_implicit());
38✔
3822

3823
   ident_t id = p_identifier();
38✔
3824
   vlog_set_ident(func, id);
38✔
3825
   vlog_set_loc(func, &state.last_loc);
38✔
3826

3827
   vlog_symtab_put(symtab, func);
38✔
3828

3829
   vlog_symtab_push(symtab, func);
38✔
3830

3831
   if (optional(tLPAREN)) {
38✔
3832
      if (peek() != tRPAREN)
13✔
3833
         p_tf_port_list(func);
10✔
3834
      consume(tRPAREN);
13✔
3835

3836
      consume(tSEMI);
13✔
3837

3838
      skip_over_attributes();
13✔
3839

3840
      while (scan_block_item_declaration()) {
16✔
3841
         p_block_item_declaration(func);
3✔
3842
         skip_over_attributes();
3✔
3843
      }
3844
   }
3845
   else {
3846
      consume(tSEMI);
25✔
3847

3848
      skip_over_attributes();
25✔
3849

3850
      while (scan_tf_item_declaration()) {
56✔
3851
         p_tf_item_declaration(func);
31✔
3852
         skip_over_attributes();
31✔
3853
      }
3854
   }
3855

3856
   while (not_at_token(tENDFUNCTION)) {
80✔
3857
      vlog_node_t s = p_statement_or_null();
42✔
3858
      if (s != NULL)
42✔
3859
         vlog_add_stmt(func, s);
42✔
3860
   }
3861

3862
   consume(tENDFUNCTION);
38✔
3863

3864
   if (optional(tCOLON)) {
38✔
3865
      ident_t name = p_identifier();
3✔
3866
      if (id != name)
3✔
3867
         error_at(&state.last_loc, "'%s' does not match function name '%s'",
1✔
3868
                  istr(name), istr(id));
3869
   }
3870

3871
   vlog_symtab_pop(symtab);
38✔
3872
}
38✔
3873

3874
static vlog_node_t p_function_declaration(void)
38✔
3875
{
3876
   // function [ lifetime ] function_body_declaration
3877

3878
   BEGIN("function declaration");
38✔
3879

3880
   vlog_node_t v = vlog_new(V_FUNC_DECL);
38✔
3881

3882
   consume(tFUNCTION);
38✔
3883

3884
   if (scan(tAUTOMATIC))
38✔
3885
      p_lifetime();
1✔
3886

3887
   p_function_body_declaration(v);
38✔
3888

3889
   vlog_set_loc(v, CURRENT_LOC);
38✔
3890
   return v;
38✔
3891
}
3892

3893
static vlog_node_t p_constant_param_expression(void)
84✔
3894
{
3895
   // mintypmax_expression | data_type | $
3896

3897
   BEGIN("constant parameter expression");
168✔
3898

3899
   return p_mintypmax_expression();
84✔
3900
}
3901

3902
static vlog_node_t p_param_assignment(vlog_node_t datatype, vlog_kind_t kind)
97✔
3903
{
3904
   // parameter_identifier { unpacked_dimension }
3905
   //   [ = constant_param_expression ]
3906

3907
   BEGIN("parameter assignment");
97✔
3908

3909
   vlog_node_t v = vlog_new(kind);
97✔
3910
   vlog_set_ident(v, p_identifier());
97✔
3911
   vlog_set_type(v, datatype);
97✔
3912

3913
   if (optional(tEQ))
97✔
3914
      vlog_set_value(v, p_constant_param_expression());
84✔
3915

3916
   vlog_set_loc(v, CURRENT_LOC);
97✔
3917
   return v;
97✔
3918
}
3919

3920
static void p_list_of_param_assignments(vlog_node_t parent,
95✔
3921
                                        vlog_node_t datatype,
3922
                                        vlog_kind_t kind)
3923
{
3924
   // param_assignment { , param_assignment }
3925

3926
   BEGIN("list of parameter assignments");
190✔
3927

3928
   do {
97✔
3929
      vlog_node_t v = p_param_assignment(datatype, kind);
97✔
3930
      vlog_symtab_put(symtab, v);
97✔
3931
      vlog_add_decl(parent, v);
97✔
3932
   } while (peek_nth(2) == tID && optional(tCOMMA));
97✔
3933
}
95✔
3934

3935
static void p_parameter_declaration(vlog_node_t mod)
67✔
3936
{
3937
   // parameter data_type_or_implicit list_of_param_assignments
3938

3939
   BEGIN("parameter declaration");
134✔
3940

3941
   consume(tPARAMETER);
67✔
3942

3943
   vlog_node_t dt = p_data_type_or_implicit();
67✔
3944
   p_list_of_param_assignments(mod, dt, param_kind);
67✔
3945
}
67✔
3946

3947
static void p_local_parameter_declaration(vlog_node_t mod)
26✔
3948
{
3949
   // localparam data_type_or_implicit list_of_param_assignments
3950

3951
   BEGIN("local parameter declaration");
52✔
3952

3953
   consume(tLOCALPARAM);
26✔
3954

3955
   vlog_node_t dt = p_data_type_or_implicit();
26✔
3956
   p_list_of_param_assignments(mod, dt, V_LOCALPARAM);
26✔
3957
}
26✔
3958

3959
static void p_class_property(vlog_node_t parent)
13✔
3960
{
3961
   // { property_qualifier } data_declaration
3962
   //   | const { class_item_qualifier } data_type const_identifier
3963
   //       [ = constant_expression ] ;
3964

3965
   BEGIN("class property");
26✔
3966

3967
   p_data_declaration(parent);
13✔
3968
}
13✔
3969

3970
static void p_class_constructor_arg(vlog_node_t parent)
2✔
3971
{
3972
   // tf_port_item | default
3973

3974
   BEGIN("class constructor argument");
4✔
3975

3976
   vlog_node_t v = p_tf_port_item();
2✔
3977
   vlog_symtab_put(symtab, v);
2✔
3978
   vlog_add_param(parent, v);
2✔
3979
}
2✔
3980

3981
static void p_class_constructor_arg_list(vlog_node_t parent)
2✔
3982
{
3983
   // class_constructor_arg { , class_constructor_arg }
3984

3985
   BEGIN("class constructor argument list");
4✔
3986

3987
   do {
2✔
3988
      p_class_constructor_arg(parent);
2✔
3989
   } while (optional(tCOMMA));
2✔
3990
}
2✔
3991

3992
static vlog_node_t p_class_constructor_declaration(void)
2✔
3993
{
3994
   // function [ class_scope ] new [ ( [ class_constructor_arg_list ] ) ] ;
3995
   //   { block_item_declaration }
3996
   //   [ super . new [ ( [ list_of_arguments | default ] ) ] ; ]
3997
   //   { function_statement_or_null }
3998
   //   endfunction [ : new]
3999

4000
   BEGIN("class constructor declaration");
2✔
4001

4002
   consume(tFUNCTION);
2✔
4003
   consume(tNEW);
2✔
4004

4005
   vlog_node_t v = vlog_new(V_CONSTRUCTOR);
2✔
4006
   vlog_set_ident(v, ident_new("new"));
2✔
4007

4008
   vlog_symtab_push(symtab, v);
2✔
4009

4010
   if (optional(tLPAREN)) {
2✔
4011
      if (not_at_token(tRPAREN))
2✔
4012
         p_class_constructor_arg_list(v);
2✔
4013

4014
      consume(tRPAREN);
2✔
4015
   }
4016

4017
   consume(tSEMI);
2✔
4018

4019
   skip_over_attributes();
2✔
4020

4021
   while (scan_block_item_declaration()) {
2✔
UNCOV
4022
      p_block_item_declaration(v);
×
UNCOV
4023
      skip_over_attributes();
×
4024
   }
4025

4026
   if (optional(tSUPER)) {
2✔
4027
      consume(tDOT);
1✔
4028
      consume(tNEW);
1✔
4029

4030
      vlog_node_t call = vlog_new(V_SUPER_CALL);
1✔
4031
      vlog_set_loc(call, &state.last_loc);
1✔
4032

4033
      if (optional(tLPAREN)) {
1✔
4034
         p_list_of_arguments(call);
1✔
4035
         consume(tRPAREN);
1✔
4036
      }
4037

4038
      vlog_add_stmt(v, call);
1✔
4039
   }
4040

4041
   while (not_at_token(tENDFUNCTION)) {
5✔
4042
      vlog_node_t s = p_statement_or_null();
3✔
4043
      if (s != NULL)
3✔
4044
         vlog_add_stmt(v, s);
2✔
4045
   }
4046

4047
   consume(tENDFUNCTION);
2✔
4048

4049
   if (optional(tCOLON))
2✔
4050
      consume(tNEW);
2✔
4051

4052
   vlog_symtab_pop(symtab);
2✔
4053

4054
   vlog_set_loc(v, CURRENT_LOC);
2✔
4055
   return v;
2✔
4056
}
4057

4058
static void p_method_qualifier(void)
1✔
4059
{
4060
   // [ pure ] virtual | class_item_qualifier
4061

4062
   BEGIN("method qualifier");
2✔
4063

4064
   consume(tVIRTUAL);
1✔
4065
}
1✔
4066

4067
static void p_class_method(vlog_node_t class)
3✔
4068
{
4069
   // { method_qualifier } task_declaration
4070
   //    | { method_qualifier } function_declaration
4071
   //    | pure virtual { class_item_qualifier } method_prototype ;
4072
   //    | extern { method_qualifier } method_prototype ;
4073
   //    | { method_qualifier } class_constructor_declaration
4074
   //    | extern { method_qualifier } class_constructor_prototype
4075

4076
   BEGIN("class method");
6✔
4077

4078
   if (scan(tVIRTUAL))
3✔
4079
      p_method_qualifier();
1✔
4080

4081
   switch (peek()) {
3✔
4082
   case tFUNCTION:
3✔
4083
      if (peek_nth(2) == tNEW)
3✔
4084
         vlog_add_decl(class, p_class_constructor_declaration());
2✔
4085
      else
4086
         vlog_add_decl(class, p_function_declaration());
1✔
4087
      break;
UNCOV
4088
   default:
×
UNCOV
4089
      one_of(tFUNCTION);
×
UNCOV
4090
      break;
×
4091
   }
4092
}
3✔
4093

4094
static void p_class_item(vlog_node_t parent)
17✔
4095
{
4096
   // { attribute_instance } class_property
4097
   //   | { attribute_instance } class_method
4098
   //   | { attribute_instance } class_constraint
4099
   //   | { attribute_instance } class_declaration
4100
   //   | { attribute_instance } covergroup_declaration
4101
   //   | local_parameter_declaration ;
4102
   //   | parameter_declaration | ;
4103

4104
   BEGIN("class item");
34✔
4105

4106
   optional_attributes();
17✔
4107

4108
   switch (peek()) {
17✔
4109
   case tSEMI:
1✔
4110
      consume(tSEMI);
1✔
4111
      break;
1✔
4112
   case tFUNCTION:
3✔
4113
   case tTASK:
4114
   case tVIRTUAL:
4115
      p_class_method(parent);
3✔
4116
      break;
3✔
4117
   default:
13✔
4118
      p_class_property(parent);
13✔
4119
      break;
13✔
4120
   }
4121
}
17✔
4122

4123
static void p_class_type(void)
2✔
4124
{
4125
   // ps_class_identifier [ parameter_value_assignment ]
4126
   //   { :: class_identifier [ parameter_value_assignment ] }
4127

4128
   BEGIN("class type");
4✔
4129

4130
   (void)p_identifier();
2✔
4131
}
2✔
4132

4133
static vlog_node_t p_class_declaration(void)
11✔
4134
{
4135
   // [ virtual ] class [ lifetime ] class_identifier [ parameter_port_list ]
4136
   //   [ extends class_type [ ( list_of_arguments ) ] ]
4137
   //   [ implements interface_class_type { , interface_class_type } ] ;
4138
   //   { class_item } endclass [ : class_identifier ]
4139

4140
   BEGIN("class declaration");
11✔
4141

4142
   vlog_node_t v = vlog_new(V_CLASS_DECL);
11✔
4143

4144
   optional(tVIRTUAL);
11✔
4145

4146
   consume(tCLASS);
11✔
4147

4148
   ident_t name = p_identifier();
11✔
4149
   vlog_set_ident(v, name);
11✔
4150

4151
   if (optional(tEXTENDS))
11✔
4152
      p_class_type();
2✔
4153

4154
   consume(tSEMI);
11✔
4155

4156
   vlog_symtab_push(symtab, v);
11✔
4157

4158
   while (not_at_token(tENDCLASS))
28✔
4159
      p_class_item(v);
17✔
4160

4161
   vlog_symtab_pop(symtab);
11✔
4162

4163
   consume(tENDCLASS);
11✔
4164

4165
   if (optional(tCOLON)) {
11✔
4166
      ident_t end_name = p_identifier();
9✔
4167
      if (name != end_name)
9✔
4168
         error_at(&state.last_loc, "'%s' does not match class name '%s'",
1✔
4169
                  istr(end_name), istr(name));
4170
   }
4171

4172
   vlog_set_loc(v, CURRENT_LOC);
11✔
4173
   vlog_symtab_put(symtab, v);
11✔
4174
   return v;
11✔
4175
}
4176

4177
static void p_block_item_declaration(vlog_node_t parent)
19✔
4178
{
4179
   // { attribute_instance } data_declaration
4180
   //   | { attribute_instance } local_parameter_declaration ;
4181
   //   | { attribute_instance } parameter_declaration ;
4182
   //   | { attribute_instance } overload_declaration
4183
   //   | { attribute_instance } let_declaration
4184

4185
   BEGIN("block item declaration");
19✔
4186

4187
   optional_attributes();
19✔
4188

4189
   switch (peek()) {
19✔
4190
   case tREG:
19✔
4191
   case tSTRUCT:
4192
   case tUNION:
4193
   case tTYPEDEF:
4194
   case tENUM:
4195
   case tSVINT:
4196
   case tINTEGER:
4197
   case tSVREAL:
4198
   case tSHORTREAL:
4199
   case tREALTIME:
4200
   case tBIT:
4201
   case tLOGIC:
4202
   case tSHORTINT:
4203
   case tTIME:
4204
      p_data_declaration(parent);
19✔
4205
      break;
19✔
UNCOV
4206
   default:
×
4207
      should_not_reach_here();
4208
   }
4209
}
19✔
4210

4211
static void p_package_or_generate_item_declaration(vlog_node_t parent)
970✔
4212
{
4213
   // net_declaration | data_declaration | task_declaration
4214
   //   | function_declaration | checker_declaration | dpi_import_export
4215
   //   | extern_constraint_declaration | class_declaration
4216
   //   | class_constructor_declaration | local_parameter_declaration ;
4217
   //   | parameter_declaration ; | covergroup_declaration
4218
   //   | overload_declaration | assertion_item_declaration | ;
4219

4220
   BEGIN("package or generate item declaration");
1,940✔
4221

4222
   switch (peek()) {
970✔
4223
   case tWIRE:
254✔
4224
   case tUWIRE:
4225
   case tSUPPLY0:
4226
   case tSUPPLY1:
4227
   case tTRI:
4228
   case tTRI0:
4229
   case tTRI1:
4230
   case tTRIAND:
4231
   case tTRIOR:
4232
   case tTRIREG:
4233
   case tWAND:
4234
   case tWOR:
4235
   case tINTERCONNECT:
4236
      p_net_declaration(parent);
254✔
4237
      break;
254✔
4238
   case tREG:
579✔
4239
   case tSTRUCT:
4240
   case tUNION:
4241
   case tTYPEDEF:
4242
   case tENUM:
4243
   case tSVINT:
4244
   case tINTEGER:
4245
   case tSVREAL:
4246
   case tSHORTREAL:
4247
   case tREALTIME:
4248
   case tTIME:
4249
   case tEVENT:
4250
   case tID:
4251
   case tVAR:
4252
   case tLOGIC:
4253
   case tBIT:
4254
   case tSHORTINT:
4255
   case tLONGINT:
4256
   case tBYTE:
4257
   case tSTRINGK:
4258
   case tIMPORT:
4259
      p_data_declaration(parent);
579✔
4260
      break;
579✔
4261
   case tTASK:
14✔
4262
      vlog_add_decl(parent, p_task_declaration());
14✔
4263
      break;
14✔
4264
   case tFUNCTION:
37✔
4265
      vlog_add_decl(parent, p_function_declaration());
37✔
4266
      break;
37✔
4267
   case tLOCALPARAM:
22✔
4268
      p_local_parameter_declaration(parent);
22✔
4269
      consume(tSEMI);
22✔
4270
      break;
22✔
4271
   case tPARAMETER:
53✔
4272
      p_parameter_declaration(parent);
53✔
4273
      consume(tSEMI);
53✔
4274
      break;
53✔
4275
   case tCLASS:
11✔
4276
   case tVIRTUAL:
4277
      vlog_add_decl(parent, p_class_declaration());
11✔
4278
      break;
11✔
UNCOV
4279
   default:
×
4280
      one_of(tWIRE, tUWIRE, tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND,
×
4281
             tTRIOR, tTRIREG, tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION,
4282
             tTYPEDEF, tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME,
4283
             tTIME, tEVENT, tID, tVAR, tLOGIC, tBIT, tSHORTINT, tLONGINT, tBYTE,
4284
             tSTRINGK, tIMPORT, tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER,
4285
             tCLASS, tVIRTUAL);
UNCOV
4286
      drop_tokens_until(tSEMI);
×
UNCOV
4287
      break;
×
4288
   }
4289
}
970✔
4290

4291
static void p_list_of_genvar_identifiers(vlog_node_t mod, vlog_node_t dt)
11✔
4292
{
4293
   // genvar_identifier { , genvar_identifier }
4294

4295
   BEGIN("list of genvar identifiers");
22✔
4296

4297
   do {
11✔
4298
      vlog_node_t v = vlog_new(V_GENVAR_DECL);
11✔
4299
      vlog_set_ident(v, p_identifier());
11✔
4300
      vlog_set_type(v, dt);
11✔
4301
      vlog_set_loc(v, CURRENT_LOC);
11✔
4302

4303
      vlog_add_decl(mod, v);
11✔
4304

4305
      vlog_symtab_put(symtab, v);
11✔
4306
   } while (optional(tCOMMA));
11✔
4307
}
11✔
4308

4309
static void p_genvar_declaration(vlog_node_t mod)
11✔
4310
{
4311
   // genvar list_of_genvar_identifiers ;
4312

4313
   BEGIN("genvar declaration");
22✔
4314

4315
   consume(tGENVAR);
11✔
4316

4317
   vlog_node_t dt = vlog_new(V_DATA_TYPE);
11✔
4318
   vlog_set_subkind(dt, DT_INTEGER);
11✔
4319
   vlog_set_loc(dt, &state.last_loc);
11✔
4320

4321
   p_list_of_genvar_identifiers(mod, dt);
11✔
4322

4323
   consume(tSEMI);
11✔
4324
}
11✔
4325

4326
static void p_module_or_generate_item_declaration(vlog_node_t mod)
974✔
4327
{
4328
   // package_or_generate_item_declaration | genvar_declaration
4329
   //   | clocking_declaration | default clocking clocking_identifier ;
4330
   //   | default disable iff expression_or_dist ;
4331

4332
   BEGIN("module or generate item declaration");
1,948✔
4333

4334
   switch (peek()) {
974✔
4335
   case tGENVAR:
11✔
4336
      p_genvar_declaration(mod);
11✔
4337
      break;
11✔
4338
   default:
963✔
4339
      p_package_or_generate_item_declaration(mod);
963✔
4340
      break;
963✔
4341
   }
4342
}
974✔
4343

4344
static void p_generate_item(vlog_node_t parent)
84✔
4345
{
4346
   // module_or_generate_item | interface_or_generate_item
4347
   //   | checker_or_generate_item
4348

4349
   BEGIN("generate item");
168✔
4350

4351
   p_module_or_generate_item(parent);
84✔
4352
}
84✔
4353

4354
static vlog_node_t p_generate_block(void)
49✔
4355
{
4356
   // generate_item
4357
   //   | [ generate_block_identifier : ] begin [ : generate_block_identifier ]
4358
   //         { generate_item } end [ : generate_block_identifier ]
4359

4360
   BEGIN("generate block");
49✔
4361

4362
   vlog_node_t b = vlog_new(V_BLOCK);
49✔
4363

4364
   if (scan(tID, tBEGIN)) {
49✔
4365
      if (peek() == tID) {
30✔
4366
         vlog_set_ident(b, p_identifier());
1✔
4367
         consume(tCOLON);
1✔
4368
      }
4369

4370
      consume(tBEGIN);
30✔
4371

4372
      if (optional(tCOLON)) {
30✔
4373
         ident_t name = p_identifier();
7✔
4374
         if (vlog_has_ident(b))    // 1800-2023 section 9.3.5
7✔
4375
            parse_error(&state.last_loc, "cannot specify both a label and a "
1✔
4376
                        "name for the same block");
4377
         else
4378
            vlog_set_ident(b, name);
6✔
4379
      }
4380

4381
      vlog_symtab_push(symtab, b);
30✔
4382

4383
      while (not_at_token(tEND))
88✔
4384
         p_generate_item(b);
58✔
4385

4386
      vlog_symtab_pop(symtab);
30✔
4387

4388
      consume(tEND);
30✔
4389

4390
      if (optional(tCOLON)) {
30✔
4391
         ident_t name = p_identifier();
2✔
4392
         if (!vlog_has_ident(b))
2✔
4393
            parse_error(&state.last_loc, "block does not have a label");
1✔
4394
         else if (name != vlog_ident(b))
1✔
4395
            parse_error(&state.last_loc, "'%s' does not match label '%s'",
1✔
4396
                        istr(name), istr(vlog_ident(b)));
4397
      }
4398
   }
4399
   else
4400
      p_generate_item(b);
19✔
4401

4402
   if (!vlog_has_ident(b))
49✔
4403
      vlog_set_ident(b, default_label("genblk"));
42✔
4404

4405
   vlog_set_loc(b, CURRENT_LOC);
49✔
4406
   return b;
49✔
4407
}
4408

4409
static vlog_node_t p_if_generate_construct(void)
26✔
4410
{
4411
   // if ( constant_expression ) generate_block [ else generate_block ]
4412

4413
   BEGIN("if generate construct");
26✔
4414

4415
   vlog_node_t v = vlog_new(V_IF_GENERATE);
26✔
4416

4417
   consume(tIF);
26✔
4418
   consume(tLPAREN);
26✔
4419

4420
   vlog_node_t c0 = vlog_new(V_COND);
26✔
4421
   vlog_set_value(c0, p_constant_expression());
26✔
4422

4423
   consume(tRPAREN);
26✔
4424

4425
   vlog_set_loc(c0, CURRENT_LOC);
26✔
4426
   vlog_add_stmt(c0, p_generate_block());
26✔
4427

4428
   vlog_add_cond(v, c0);
26✔
4429

4430
   if (optional(tELSE)) {
26✔
4431
      vlog_node_t c1 = vlog_new(V_COND);
11✔
4432
      vlog_set_loc(c1, &state.last_loc);
11✔
4433
      vlog_add_stmt(c1, p_generate_block());
11✔
4434

4435
      vlog_add_cond(v, c1);
11✔
4436
   }
4437

4438
   vlog_set_loc(v, CURRENT_LOC);
26✔
4439
   return v;
26✔
4440
}
4441

4442
static vlog_node_t p_conditional_generate_construct(void)
26✔
4443
{
4444
   // if_generate_construct | case_generate_construct
4445

4446
   BEGIN("conditional generate construct");
52✔
4447

4448
   switch (peek()) {
26✔
4449
   case tIF:
26✔
4450
      return p_if_generate_construct();
52✔
UNCOV
4451
   default:
×
4452
      should_not_reach_here();
4453
   }
4454
}
4455

4456
static vlog_node_t p_genvar_initialization(void)
12✔
4457
{
4458
   // [ genvar ] genvar_identifier = constant_expression
4459

4460
   BEGIN("genvar initialization");
12✔
4461

4462
   vlog_node_t v = vlog_new(V_FOR_INIT);
12✔
4463

4464
   vlog_node_t ref = vlog_new(V_REF);
12✔
4465
   vlog_set_ident(ref, p_identifier());
12✔
4466
   vlog_set_loc(ref, &state.last_loc);
12✔
4467

4468
   vlog_symtab_lookup(symtab, ref);
12✔
4469

4470
   consume(tEQ);
12✔
4471

4472
   vlog_node_t a = vlog_new(V_BASSIGN);
12✔
4473
   vlog_set_target(a, ref);
12✔
4474
   vlog_set_value(a, p_constant_expression());
12✔
4475
   vlog_set_loc(a, CURRENT_LOC);
12✔
4476

4477
   vlog_add_stmt(v, a);
12✔
4478

4479
   vlog_set_loc(v, CURRENT_LOC);
12✔
4480
   return v;
12✔
4481
}
4482

4483
static vlog_node_t p_genvar_iteration(void)
12✔
4484
{
4485
   // genvar_identifier assignment_operator genvar_expression
4486
   //   | inc_or_dec_operator genvar_identifier
4487
   //   | genvar_identifier inc_or_dec_operator
4488

4489
   BEGIN("genvar iteration");
12✔
4490

4491
   vlog_node_t v = vlog_new(V_FOR_STEP);
12✔
4492

4493
   vlog_node_t prefix = NULL;
12✔
4494
   if (scan(tPLUSPLUS, tMINUSMINUS)) {
12✔
4495
      prefix = vlog_new(V_PREFIX);
1✔
4496
      vlog_set_subkind(prefix, p_inc_or_dec_operator());
1✔
4497
   }
4498

4499
   vlog_node_t ref = vlog_new(V_REF);
12✔
4500
   vlog_set_ident(ref, p_identifier());
12✔
4501
   vlog_set_loc(ref, &state.last_loc);
12✔
4502

4503
   vlog_symtab_lookup(symtab, ref);
12✔
4504

4505
   if (prefix != NULL) {
12✔
4506
      vlog_set_target(prefix, ref);
1✔
4507

4508
      vlog_add_stmt(v, prefix);
1✔
4509
   }
4510
   else if (optional(tEQ)) {
11✔
4511
      vlog_node_t a = vlog_new(V_BASSIGN);
10✔
4512
      vlog_set_target(a, ref);
10✔
4513
      vlog_set_value(a, p_constant_expression());
10✔
4514

4515
      vlog_add_stmt(v, a);
10✔
4516
   }
4517
   else {
4518
      vlog_node_t a = vlog_new(V_POSTFIX);
1✔
4519
      vlog_set_subkind(a, p_inc_or_dec_operator());
1✔
4520
      vlog_set_target(a, ref);
1✔
4521

4522
      vlog_add_stmt(v, a);
1✔
4523
   }
4524

4525
   vlog_set_loc(v, CURRENT_LOC);
12✔
4526
   return v;
12✔
4527
}
4528

4529
static vlog_node_t p_loop_generate_construct(void)
12✔
4530
{
4531
   // for ( genvar_initialization ; genvar_expression ; genvar_iteration )
4532
   //   generate_block
4533

4534
   BEGIN("loop generate construct");
12✔
4535

4536
   consume(tFOR);
12✔
4537
   consume(tLPAREN);
12✔
4538

4539
   vlog_node_t v = vlog_new(V_FOR_GENERATE);
12✔
4540

4541
   vlog_symtab_push(symtab, v);
12✔
4542

4543
   vlog_set_left(v, p_genvar_initialization());
12✔
4544

4545
   consume(tSEMI);
12✔
4546

4547
   vlog_set_value(v, p_constant_expression());
12✔
4548

4549
   consume(tSEMI);
12✔
4550

4551
   vlog_set_right(v, p_genvar_iteration());
12✔
4552

4553
   consume(tRPAREN);
12✔
4554

4555
   vlog_add_stmt(v, p_generate_block());
12✔
4556

4557
   vlog_symtab_pop(symtab);
12✔
4558

4559
   vlog_set_loc(v, CURRENT_LOC);
12✔
4560
   return v;
12✔
4561
}
4562

4563
static void p_module_common_item(vlog_node_t mod)
1,726✔
4564
{
4565
   // module_or_generate_item_declaration
4566
   //   | interface_instantiation | program_instantiation
4567
   //   | assertion_item | bind_directive | continuous_assign
4568
   //   | net_alias | initial_construct | final_construct
4569
   //   | always_construct | loop_generate_construct
4570
   //   | conditional_generate_construct | elaboration_system_task
4571

4572
   BEGIN("module common item");
3,452✔
4573

4574
   switch (peek()) {
1,726✔
4575
   case tALWAYS:
163✔
4576
   case tALWAYSCOMB:
4577
   case tALWAYSFF:
4578
   case tALWAYSLATCH:
4579
      vlog_add_stmt(mod, p_always_construct());
163✔
4580
      break;
163✔
4581
   case tINITIAL:
320✔
4582
      vlog_add_stmt(mod, p_initial_construct());
320✔
4583
      break;
320✔
4584
   case tWIRE:
959✔
4585
   case tUWIRE:
4586
   case tSUPPLY0:
4587
   case tSUPPLY1:
4588
   case tTRI:
4589
   case tTRI0:
4590
   case tTRI1:
4591
   case tTRIAND:
4592
   case tTRIOR:
4593
   case tTRIREG:
4594
   case tWAND:
4595
   case tWOR:
4596
   case tINTERCONNECT:
4597
   case tREG:
4598
   case tSTRUCT:
4599
   case tUNION:
4600
   case tTYPEDEF:
4601
   case tENUM:
4602
   case tSVINT:
4603
   case tINTEGER:
4604
   case tSVREAL:
4605
   case tSHORTREAL:
4606
   case tREALTIME:
4607
   case tTIME:
4608
   case tTASK:
4609
   case tFUNCTION:
4610
   case tLOCALPARAM:
4611
   case tPARAMETER:
4612
   case tEVENT:
4613
   case tID:
4614
   case tGENVAR:
4615
   case tVAR:
4616
   case tLOGIC:
4617
   case tBIT:
4618
   case tSHORTINT:
4619
   case tLONGINT:
4620
   case tBYTE:
4621
   case tSTRINGK:
4622
   case tIMPORT:
4623
      p_module_or_generate_item_declaration(mod);
959✔
4624
      break;
959✔
4625
   case tASSIGN:
246✔
4626
      p_continuous_assign(mod);
246✔
4627
      break;
246✔
4628
   case tFOR:
12✔
4629
      vlog_add_stmt(mod, p_loop_generate_construct());
12✔
4630
      break;
12✔
4631
   case tIF:
26✔
4632
      vlog_add_stmt(mod, p_conditional_generate_construct());
26✔
4633
      break;
26✔
UNCOV
4634
   default:
×
UNCOV
4635
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
×
4636
             tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
4637
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM,
4638
             tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTIME, tTASK,
4639
             tFUNCTION, tPARAMETER, tLOCALPARAM, tEVENT, tID, tGENVAR, tVAR,
4640
             tLOGIC, tBIT, tSHORTINT, tLONGINT, tBYTE, tSTRINGK, tIMPORT,
4641
             tASSIGN, tFOR, tIF);
UNCOV
4642
      drop_tokens_until(tSEMI);
×
4643
   }
4644
}
1,726✔
4645

4646
static vlog_strength_t p_strength0(void)
10✔
4647
{
4648
   // supply0 | strong0 | pull0 | weak0
4649

4650
   BEGIN("strength0");
20✔
4651

4652
   switch (one_of(tSUPPLY0, tSTRONG0, tPULL0, tWEAK0)) {
10✔
4653
   default:
4654
   case tSUPPLY0: return V_STRENGTH_SUPPLY;
4655
   case tSTRONG0: return V_STRENGTH_STRONG;
4656
   case tPULL0:   return V_STRENGTH_PULL;
4657
   case tWEAK0:   return V_STRENGTH_WEAK;
4658
   }
4659
}
4660

4661
static vlog_strength_t p_strength1(void)
11✔
4662
{
4663
   // supply1 | strong1 | pull1 | weak1
4664

4665
   BEGIN("strength1");
22✔
4666

4667
   switch (one_of(tSUPPLY1, tSTRONG1, tPULL1, tWEAK1)) {
11✔
4668
   default:
4669
   case tSUPPLY1: return V_STRENGTH_SUPPLY;
4670
   case tSTRONG1: return V_STRENGTH_STRONG;
4671
   case tPULL1:   return V_STRENGTH_PULL;
4672
   case tWEAK1:   return V_STRENGTH_WEAK;
4673
   }
4674
}
4675

4676
static vlog_node_t p_pulldown_strength(void)
2✔
4677
{
4678
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength0 )
4679

4680
   BEGIN("pulldown strength");
2✔
4681

4682
   consume(tLPAREN);
2✔
4683

4684
   vlog_strength_t s0, s1;
2✔
4685
   switch (peek()) {
2✔
4686
   case tSUPPLY1:
×
4687
   case tSTRONG1:
4688
   case tPULL1:
4689
   case tWEAK1:
UNCOV
4690
      s1 = p_strength1();
×
4691
      consume(tCOMMA);
×
UNCOV
4692
      s0 = p_strength0();
×
UNCOV
4693
      break;
×
4694
   default:
2✔
4695
      s0 = s1 = p_strength0();
2✔
4696
      if (optional(tCOMMA))
2✔
UNCOV
4697
         s1 = p_strength1();
×
4698
      break;
4699
   }
4700

4701
   consume(tRPAREN);
2✔
4702

4703
   vlog_node_t v = vlog_new(V_STRENGTH);
2✔
4704
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
2✔
4705
   vlog_set_loc(v, CURRENT_LOC);
2✔
4706
   return v;
2✔
4707
}
4708

4709
static vlog_node_t p_pullup_strength(void)
6✔
4710
{
4711
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength1 )
4712

4713
   BEGIN("pullup strength");
6✔
4714

4715
   consume(tLPAREN);
6✔
4716

4717
   vlog_strength_t s0, s1;
6✔
4718
   switch (peek()) {
6✔
4719
   case tSUPPLY0:
1✔
4720
   case tSTRONG0:
4721
   case tPULL0:
4722
   case tWEAK0:
4723
      s0 = p_strength0();
1✔
4724
      consume(tCOMMA);
1✔
4725
      s1 = p_strength1();
1✔
4726
      break;
1✔
4727
   default:
5✔
4728
      s1 = s0 = p_strength1();
5✔
4729
      if (optional(tCOMMA))
5✔
4730
         s0 = p_strength0();
1✔
4731
      break;
4732
   }
4733

4734
   consume(tRPAREN);
6✔
4735

4736
   vlog_node_t v = vlog_new(V_STRENGTH);
6✔
4737
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
6✔
4738
   vlog_set_loc(v, CURRENT_LOC);
6✔
4739
   return v;
6✔
4740
}
4741

4742
static vlog_node_t p_pull_gate_instance(vlog_gate_kind_t kind, vlog_node_t st)
19✔
4743
{
4744
   // [ name_of_instance ] ( output_terminal )
4745

4746
   BEGIN("pull gate instance");
19✔
4747

4748
   vlog_node_t v = vlog_new(V_GATE_INST);
19✔
4749
   vlog_set_subkind(v, kind);
19✔
4750
   vlog_add_param(v, st);
19✔
4751

4752
   if (peek() == tID) {
19✔
4753
      vlog_set_ident(v, p_identifier());
7✔
4754
      vlog_set_loc(v, &state.last_loc);
7✔
4755
      vlog_symtab_put(symtab, v);
7✔
4756
   }
4757
   else
4758
      vlog_set_ident(v, default_label("gate"));
12✔
4759

4760
   consume(tLPAREN);
19✔
4761

4762
   vlog_symtab_set_implicit(symtab, implicit_kind);
19✔
4763

4764
   vlog_set_target(v, p_net_lvalue());
19✔
4765

4766
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
19✔
4767

4768
   consume(tRPAREN);
19✔
4769

4770
   vlog_set_loc(v, CURRENT_LOC);
19✔
4771
   return v;
19✔
4772
}
4773

4774
static vlog_node_t p_n_terminal_gate_instance(vlog_gate_kind_t kind,
27✔
4775
                                              vlog_node_t st)
4776
{
4777
   // [ name_of_instance ] ( output_terminal , input_terminal
4778
   //     { , input_terminal } )
4779

4780
   BEGIN("N-terminal gate instance");
27✔
4781

4782
   vlog_node_t v = vlog_new(V_GATE_INST);
27✔
4783
   vlog_set_subkind(v, kind);
27✔
4784

4785
   if (peek() == tID) {
27✔
4786
      vlog_set_ident(v, p_identifier());
5✔
4787
      vlog_set_loc(v, &state.last_loc);
5✔
4788
      vlog_symtab_put(symtab, v);
5✔
4789
   }
4790
   else
4791
      vlog_set_ident(v, default_label("gate"));
22✔
4792

4793
   consume(tLPAREN);
27✔
4794

4795
   vlog_symtab_set_implicit(symtab, implicit_kind);
27✔
4796

4797
   vlog_set_target(v, p_net_lvalue());
27✔
4798

4799
   consume(tCOMMA);
27✔
4800

4801
   do {
43✔
4802
      vlog_add_param(v, p_expression());
43✔
4803
   } while (optional(tCOMMA));
43✔
4804

4805
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
27✔
4806

4807
   consume(tRPAREN);
27✔
4808

4809
   vlog_set_loc(v, CURRENT_LOC);
27✔
4810
   return v;
27✔
4811
}
4812

4813
static vlog_node_t p_enable_gate_instance(vlog_gate_kind_t kind)
1✔
4814
{
4815
   // [ name_of_instance ] ( output_terminal , input_terminal ,
4816
   //     enable_terminal )
4817

4818
   BEGIN("enable gate instance");
1✔
4819

4820
   vlog_node_t v = vlog_new(V_GATE_INST);
1✔
4821
   vlog_set_subkind(v, kind);
1✔
4822

4823
   if (peek() == tID) {
1✔
UNCOV
4824
      vlog_set_ident(v, p_identifier());
×
UNCOV
4825
      vlog_set_loc(v, &state.last_loc);
×
UNCOV
4826
      vlog_symtab_put(symtab, v);
×
4827
   }
4828
   else
4829
      vlog_set_ident(v, default_label("gate"));
1✔
4830

4831
   consume(tLPAREN);
1✔
4832

4833
   vlog_symtab_set_implicit(symtab, implicit_kind);
1✔
4834

4835
   vlog_set_target(v, p_net_lvalue());
1✔
4836

4837
   consume(tCOMMA);
1✔
4838

4839
   vlog_add_param(v, p_expression());
1✔
4840

4841
   consume(tCOMMA);
1✔
4842

4843
   vlog_add_param(v, p_expression());
1✔
4844

4845
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
1✔
4846

4847
   consume(tRPAREN);
1✔
4848

4849
   vlog_set_loc(v, CURRENT_LOC);
1✔
4850
   return v;
1✔
4851
}
4852

4853
static vlog_node_t p_pass_switch_instance(vlog_gate_kind_t kind)
1✔
4854
{
4855
   // [ name_of_instance ] ( inout_terminal , inout_terminal )
4856

4857
   BEGIN("pass switch instance");
1✔
4858

4859
   vlog_node_t v = vlog_new(V_GATE_INST);
1✔
4860
   vlog_set_subkind(v, kind);
1✔
4861

4862
   if (peek() == tID) {
1✔
UNCOV
4863
      vlog_set_ident(v, p_identifier());
×
UNCOV
4864
      vlog_set_loc(v, &state.last_loc);
×
UNCOV
4865
      vlog_symtab_put(symtab, v);
×
4866
   }
4867
   else
4868
      vlog_set_ident(v, default_label("gate"));
1✔
4869

4870
   consume(tLPAREN);
1✔
4871

4872
   vlog_symtab_set_implicit(symtab, implicit_kind);
1✔
4873

4874
   vlog_set_target(v, p_net_lvalue());
1✔
4875

4876
   consume(tCOMMA);
1✔
4877

4878
   vlog_add_param(v, p_net_lvalue());
1✔
4879

4880
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
1✔
4881

4882
   consume(tRPAREN);
1✔
4883

4884
   vlog_set_loc(v, CURRENT_LOC);
1✔
4885
   return v;
1✔
4886
}
4887

4888
static vlog_node_t p_pass_enable_switch_instance(vlog_gate_kind_t kind)
1✔
4889
{
4890
   // [ name_of_instance ] ( inout_terminal , inout_terminal ,
4891
   //     enable_terminal )
4892

4893
   BEGIN("pass enable switch instance");
1✔
4894

4895
   vlog_node_t v = vlog_new(V_GATE_INST);
1✔
4896
   vlog_set_subkind(v, kind);
1✔
4897

4898
   if (peek() == tID) {
1✔
UNCOV
4899
      vlog_set_ident(v, p_identifier());
×
UNCOV
4900
      vlog_set_loc(v, &state.last_loc);
×
UNCOV
4901
      vlog_symtab_put(symtab, v);
×
4902
   }
4903
   else
4904
      vlog_set_ident(v, default_label("gate"));
1✔
4905

4906
   consume(tLPAREN);
1✔
4907

4908
   vlog_symtab_set_implicit(symtab, implicit_kind);
1✔
4909

4910
   vlog_set_target(v, p_net_lvalue());
1✔
4911

4912
   consume(tCOMMA);
1✔
4913

4914
   vlog_add_param(v, p_net_lvalue());
1✔
4915

4916
   consume(tCOMMA);
1✔
4917

4918
   vlog_add_param(v, p_expression());
1✔
4919

4920
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
1✔
4921

4922
   consume(tRPAREN);
1✔
4923

4924
   vlog_set_loc(v, CURRENT_LOC);
1✔
4925
   return v;
1✔
4926
}
4927

4928
static void p_gate_instantiation(vlog_node_t mod)
49✔
4929
{
4930
   // cmos_switchtype [ delay3 ] cmos_switch_instance
4931
   //     { , cmos_switch_instance } ;
4932
   //  | enable_gatetype [ drive_strength ] [ delay3 ]
4933
   //     enable_gate_instance { , enable_gate_instance } ;
4934
   //  | mos_switchtype [ delay3 ] mos_switch_instance
4935
   //     { , mos_switch_instance } ;
4936
   //  | n_input_gatetype [ drive_strength ] [ delay2 ] n_input_gate_instance
4937
   //     { , n_input_gate_instance } ;
4938
   //  | n_output_gatetype [ drive_strength ] [ delay2 ] n_output_gate_instance
4939
   //     { , n_output_gate_instance } ;
4940
   //  | pass_en_switchtype [ delay2 ] pass_enable_switch_instance
4941
   //     { , pass_enable_switch_instance } ;
4942
   //  | pass_switchtype pass_switch_instance { , pass_switch_instance } ;
4943
   //  | pulldown [ pulldown_strength ] pull_gate_instance
4944
   //     { , pull_gate_instance } ;
4945
   //  | pullup [ pullup_strength ] pull_gate_instance
4946
   //     { , pull_gate_instance } ;
4947

4948
   BEGIN("gate instantiation");
98✔
4949

4950
   token_t token = one_of(tPULLDOWN, tPULLUP, tAND, tNAND, tOR, tNOR,
49✔
4951
                          tXOR, tXNOR, tNOT, tBUF, tBUFIF0, tBUFIF1,
4952
                          tNOTIF0, tNOTIF1, tTRAN, tRTRAN, tTRANIF0, tTRANIF1,
4953
                          tRTRANIF0, tRTRANIF1);
4954

4955
   switch (token) {
49✔
4956
   case tPULLDOWN:
7✔
4957
      {
4958
         vlog_node_t st;
7✔
4959
         if (peek() == tLPAREN && peek_nth(2) != tID)
7✔
4960
            st = p_pulldown_strength();
2✔
4961
         else {
4962
            st = vlog_new(V_STRENGTH);
5✔
4963
            vlog_set_subkind(st, ST_PULLUP);
5✔
4964
         }
4965

4966
         do {
7✔
4967
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLDOWN, st);
7✔
4968
            vlog_add_stmt(mod, g);
7✔
4969
         } while (optional(tCOMMA));
7✔
4970
      }
4971
      break;
4972

4973
   case tPULLUP:
12✔
4974
      {
4975
         vlog_node_t st;
12✔
4976
         if (peek() == tLPAREN && peek_nth(2) != tID)
12✔
4977
            st = p_pullup_strength();
6✔
4978
         else {
4979
            st = vlog_new(V_STRENGTH);
6✔
4980
            vlog_set_subkind(st, ST_PULLUP);
6✔
4981
         }
4982

4983
         do {
12✔
4984
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLUP, st);
12✔
4985
            vlog_add_stmt(mod, g);
12✔
4986
         } while (optional(tCOMMA));
12✔
4987
      }
4988
      break;
4989

4990
   case tAND:
27✔
4991
   case tNAND:
4992
   case tOR:
4993
   case tNOR:
4994
   case tXOR:
4995
   case tXNOR:
4996
   case tNOT:
4997
   case tBUF:
4998
      {
4999
         vlog_node_t st;
27✔
5000
         if (peek() == tLPAREN && peek_nth(2) != tID)
27✔
5001
            st = p_drive_strength();
1✔
5002
         else {
5003
            st = vlog_new(V_STRENGTH);
26✔
5004
            vlog_set_subkind(st, ST_STRONG);
26✔
5005
         }
5006

5007
         const vlog_gate_kind_t kind = get_gate_kind(token);
27✔
5008

5009
         if (peek() == tHASH)
27✔
5010
            p_delay2();
2✔
5011

5012
         do {
27✔
5013
            vlog_add_stmt(mod, p_n_terminal_gate_instance(kind, st));
27✔
5014
         } while (optional(tCOMMA));
27✔
5015
      }
5016
      break;
5017

5018
   case tBUFIF0:
1✔
5019
   case tBUFIF1:
5020
   case tNOTIF0:
5021
   case tNOTIF1:
5022
      {
5023
         vlog_node_t st;
1✔
5024
         if (peek() == tLPAREN && peek_nth(2) != tID)
1✔
5025
            st = p_drive_strength();
1✔
5026
         else {
UNCOV
5027
            st = vlog_new(V_STRENGTH);
×
UNCOV
5028
            vlog_set_subkind(st, ST_STRONG);
×
5029
         }
5030

5031
         if (peek() == tHASH)
1✔
UNCOV
5032
            p_delay3();
×
5033

5034
         const vlog_gate_kind_t kind = get_gate_kind(token);
1✔
5035

5036
         do {
1✔
5037
            vlog_add_stmt(mod, p_enable_gate_instance(kind));
1✔
5038
         } while (optional(tCOMMA));
1✔
5039
      }
5040
      break;
5041

5042
   case tTRAN:
1✔
5043
   case tRTRAN:
5044
      {
5045
         const vlog_gate_kind_t kind = get_gate_kind(token);
1✔
5046

5047
         do {
1✔
5048
            vlog_add_stmt(mod, p_pass_switch_instance(kind));
1✔
5049
         } while (optional(tCOMMA));
1✔
5050
      }
5051
      break;
5052

5053
   case tTRANIF0:
1✔
5054
   case tTRANIF1:
5055
   case tRTRANIF0:
5056
   case tRTRANIF1:
5057
      {
5058
         if (peek() == tHASH)
1✔
UNCOV
5059
            p_delay2();
×
5060

5061
         const vlog_gate_kind_t kind = get_gate_kind(token);
1✔
5062

5063
         do {
1✔
5064
            vlog_add_stmt(mod, p_pass_enable_switch_instance(kind));
1✔
5065
         } while (optional(tCOMMA));
1✔
5066
      }
5067
      break;
5068

5069
   default:
5070
      break;
5071
   }
5072

5073
   consume(tSEMI);
49✔
5074
}
49✔
5075

5076
static vlog_node_t p_module_path_expression(void)
4✔
5077
{
5078
   // module_path_primary
5079
   //   | unary_module_path_operator { attribute_instance } module_path_primary
5080
   //   | module_path_expression binary_module_path_operator
5081
   //      { attribute_instance } module_path_expression
5082
   //   | module_path_conditional_expression
5083

5084
   BEGIN("module path expression");
8✔
5085

5086
   // TODO: sem should check valid subset
5087
   return p_expression();
4✔
5088
}
5089

5090
static void p_path_delay_expression(void)
21✔
5091
{
5092
   // constant_expression
5093
   //   | constant_expression : constant_expression : constant_expression
5094

5095
   BEGIN("path delay expression");
42✔
5096

5097
   (void)p_constant_expression();
21✔
5098
}
21✔
5099

5100
static void p_list_of_path_delay_expressions(void)
17✔
5101
{
5102
   // path_delay_expression { , path_delay_expression }
5103

5104
   BEGIN("list of path delay expressions");
34✔
5105

5106
   do {
21✔
5107
      p_path_delay_expression();
21✔
5108
   } while (optional(tCOMMA));
21✔
5109
}
17✔
5110

5111
static void p_path_delay_value(void)
17✔
5112
{
5113
   // list_of_path_delay_expressions | ( list_of_path_delay_expressions )
5114

5115
   BEGIN("path delay value");
34✔
5116

5117
   if (optional(tLPAREN)) {
17✔
5118
      p_list_of_path_delay_expressions();
4✔
5119
      consume(tRPAREN);
4✔
5120
   }
5121
   else
5122
      p_list_of_path_delay_expressions();
13✔
5123
}
17✔
5124

5125
static vlog_node_t p_specify_terminal_descriptor(void)
71✔
5126
{
5127
   // identifier [ [ constant_range_expression ] ]
5128

5129
   BEGIN("specify terminal descriptor");
71✔
5130

5131
   vlog_node_t v = vlog_new(V_REF);
71✔
5132
   vlog_set_ident(v, p_identifier());
71✔
5133
   vlog_set_loc(v, CURRENT_LOC);
71✔
5134

5135
   if (optional(tLSQUARE)) {
71✔
5136
      (void)p_constant_range_expression();
2✔
5137
      consume(tRSQUARE);
2✔
5138
   }
5139

5140
   return v;
71✔
5141
}
5142

5143
static void p_list_of_path_inputs(vlog_node_t v, vlog_node_t head)
8✔
5144
{
5145
   // specify_input_terminal_descriptor { , specify_input_terminal_descriptor }
5146

5147
   BEGIN_WITH_HEAD("list of path inputs", head);
16✔
5148

5149
   while (optional(tCOMMA))
15✔
5150
      (void)p_specify_terminal_descriptor();
7✔
5151
}
8✔
5152

5153
static void p_list_of_path_outputs(vlog_node_t v)
8✔
5154
{
5155
   // specify_output_terminal_descriptor
5156
   //     { , specify_output_terminal_descriptor }
5157

5158
   BEGIN("list of path outputs");
16✔
5159

5160
   do {
17✔
5161
      (void)p_specify_terminal_descriptor();
17✔
5162
   } while (optional(tCOMMA));
17✔
5163
}
8✔
5164

5165
static void p_polarity_operator(void)
9✔
5166
{
5167
   // + | -
5168

5169
   BEGIN("polarity operator");
18✔
5170

5171
   (void)one_of(tPLUS, tMINUS);
9✔
5172
}
9✔
5173

5174
static vlog_node_t p_parallel_path_description(vlog_node_t head)
7✔
5175
{
5176
   // ( specify_input_terminal_descriptor [ polarity_operator ]
5177
   //     => specify_output_terminal_descriptor )
5178

5179
   EXTEND("parallel path description");
7✔
5180

5181
   if (scan(tPLUS, tMINUS))
7✔
5182
      (void)p_polarity_operator();
3✔
5183

5184
   consume(tASSOC);
7✔
5185

5186
   (void)p_specify_terminal_descriptor();
7✔
5187

5188
   consume(tRPAREN);
7✔
5189
   return NULL;
7✔
5190
}
5191

5192
static vlog_node_t p_full_path_description(vlog_node_t head)
3✔
5193
{
5194
   // ( list_of_path_inputs [ polarity_operator ] *> list_of_path_outputs )
5195

5196
   EXTEND("full path description");
3✔
5197

5198
   p_list_of_path_inputs(NULL, head);
3✔
5199

5200
   if (scan(tPLUS, tMINUS))
3✔
5201
      (void)p_polarity_operator();
3✔
5202

5203
   consume(tTIMESGT);
3✔
5204

5205
   p_list_of_path_outputs(NULL);
3✔
5206

5207
   consume(tRPAREN);
3✔
5208
   return NULL;
3✔
5209
}
5210

5211
static vlog_node_t p_simple_path_declaration(void)
10✔
5212
{
5213
   // parallel_path_description = path_delay_value
5214
   //   | full_path_description = path_delay_value
5215

5216
   BEGIN("simple path declaration");
10✔
5217

5218
   // Parse up to the first terminal descriptor to determine which
5219
   // production to use
5220

5221
   consume(tLPAREN);
10✔
5222

5223
   vlog_node_t head = p_specify_terminal_descriptor();
10✔
5224

5225
   if (scan(tCOMMA, tTIMESGT) || peek_nth(2) == tTIMESGT)
10✔
5226
      (void)p_full_path_description(head);
3✔
5227
   else
5228
      (void)p_parallel_path_description(head);
7✔
5229

5230
   consume(tEQ);
10✔
5231

5232
   (void)p_path_delay_value();
10✔
5233

5234
   return NULL;
10✔
5235
}
5236

5237
static void p_edge_identifier(void)
7✔
5238
{
5239
   // posedge | negedge | edge
5240

5241
   BEGIN("edge identifier");
14✔
5242

5243
   one_of(tPOSEDGE, tNEGEDGE, tEDGE);
7✔
5244
}
7✔
5245

5246
static vlog_node_t p_parallel_edge_sensitive_path_description(vlog_node_t head)
2✔
5247
{
5248
   // ( [ edge_identifier ] specify_input_terminal_descriptor
5249
   //     [ polarity_operator ] => ( specify_output_terminal_descriptor
5250
   //     [ polarity_operator ] : data_source_expression ) )
5251

5252
   EXTEND("parallel edge sensitive path description");
2✔
5253

5254
   if (scan(tPLUS, tMINUS))
2✔
UNCOV
5255
      (void)p_polarity_operator();
×
5256

5257
   consume(tASSOC);
2✔
5258

5259
   consume(tLPAREN);
2✔
5260

5261
   (void)p_specify_terminal_descriptor();
2✔
5262

5263
   if (scan(tPLUS, tMINUS)) {
2✔
UNCOV
5264
      (void)p_polarity_operator();
×
UNCOV
5265
      consume(tCOLON);
×
5266
   }
5267
   else if (scan(tINDEXPOS, tINDEXNEG))
2✔
5268
      consume(peek());  // Lexing ambiguity with +: and -:
1✔
5269
   else
5270
      consume(tCOLON);
1✔
5271

5272
   (void)p_expression();
2✔
5273

5274
   consume(tRPAREN);
2✔
5275
   consume(tRPAREN);
2✔
5276
   return NULL;
2✔
5277
}
5278

5279
static vlog_node_t p_full_edge_sensitive_path_description(vlog_node_t head)
5✔
5280
{
5281
   // ( [ edge_identifier ] list_of_path_inputs [ polarity_operator ] *>
5282
   //     ( list_of_path_outputs [ polarity_operator ]
5283
   //     : data_source_expression ) )
5284

5285
   EXTEND("full edge sensitive path description");
5✔
5286

5287
   p_list_of_path_inputs(NULL, head);
5✔
5288

5289
   if (scan(tPLUS, tMINUS))
5✔
5290
      (void)p_polarity_operator();
3✔
5291

5292
   consume(tTIMESGT);
5✔
5293

5294
   consume(tLPAREN);
5✔
5295

5296
   p_list_of_path_outputs(NULL);
5✔
5297

5298
   if (scan(tPLUS, tMINUS)) {
5✔
UNCOV
5299
      (void)p_polarity_operator();
×
UNCOV
5300
      consume(tCOLON);
×
5301
   }
5302
   else if (scan(tINDEXPOS, tINDEXNEG))
5✔
5303
      consume(peek());  // Lexing ambiguity with +: and -:
2✔
5304
   else
5305
      consume(tCOLON);
3✔
5306

5307
   (void)p_expression();
5✔
5308

5309
   consume(tRPAREN);
5✔
5310
   consume(tRPAREN);
5✔
5311
   return NULL;
5✔
5312
}
5313

5314
static vlog_node_t p_edge_sensitive_path_declaration(void)
7✔
5315
{
5316
   // parallel_edge_sensitive_path_description = path_delay_value
5317
   //   | full_edge_sensitive_path_description = path_delay_value
5318

5319
   BEGIN("edge sensitive path declaration");
7✔
5320

5321
   // Parse up to the first terminal descriptor to determine which
5322
   // production to use
5323

5324
   consume(tLPAREN);
7✔
5325

5326
   if (scan(tEDGE, tPOSEDGE, tNEGEDGE))
7✔
5327
      p_edge_identifier();
7✔
5328

5329
   vlog_node_t head = p_specify_terminal_descriptor();
7✔
5330

5331
   if (scan(tCOMMA, tTIMESGT) || peek_nth(2) == tTIMESGT)
7✔
5332
      (void)p_full_edge_sensitive_path_description(head);
5✔
5333
   else
5334
      (void)p_parallel_edge_sensitive_path_description(head);
2✔
5335

5336
   consume(tEQ);
7✔
5337

5338
   (void)p_path_delay_value();
7✔
5339

5340
   return NULL;
7✔
5341
}
5342

5343
static vlog_node_t p_state_dependent_path_declaration(void)
6✔
5344
{
5345
   // if ( module_path_expression ) simple_path_declaration
5346
   //   | if ( module_path_expression ) edge_sensitive_path_declaration
5347
   //   | ifnone simple_path_declaration
5348

5349
   BEGIN("state dependent path declaration");
6✔
5350

5351
   switch (one_of(tIF, tIFNONE)) {
6✔
5352
   case tIF:
4✔
5353
      consume(tLPAREN);
4✔
5354
      (void)p_module_path_expression();
4✔
5355
      consume(tRPAREN);
4✔
5356
      break;
4✔
5357
   case tIFNONE:
5358
      break;
5359
   }
5360

5361
   if (peek_nth(2) == tID)
6✔
5362
      (void)p_simple_path_declaration();
2✔
5363
   else {
5364
      // This is invalid for ifnone according to the grammar but is
5365
      // accepted by some simulators and seen in the wild
5366
      (void)p_edge_sensitive_path_declaration();
4✔
5367
   }
5368

5369
   return NULL;
6✔
5370
}
5371

5372
static vlog_node_t p_path_declaration(void)
17✔
5373
{
5374
   // simple_path_declaration ;
5375
   //  | edge_sensitive_path_declaration ;
5376
   //  | state_dependent_path_declaration ;
5377

5378
   BEGIN("path declaration");
17✔
5379

5380
   switch (peek()) {
17✔
5381
   case tIF:
6✔
5382
   case tIFNONE:
5383
      (void)p_state_dependent_path_declaration();
6✔
5384
      break;
6✔
5385
   case tLPAREN:
11✔
5386
      switch (peek_nth(2)) {
11✔
5387
      case tEDGE:
3✔
5388
      case tNEGEDGE:
5389
      case tPOSEDGE:
5390
         (void)p_edge_sensitive_path_declaration();
3✔
5391
         break;
3✔
5392
      default:
8✔
5393
         (void)p_simple_path_declaration();
8✔
5394
         break;
8✔
5395
      }
5396
      break;
UNCOV
5397
   default:
×
UNCOV
5398
      one_of(tIF, tIFNONE);
×
5399
   }
5400

5401
   consume(tSEMI);
17✔
5402
   return NULL;
17✔
5403
}
5404

5405
static void p_timing_check_event_control(void)
5✔
5406
{
5407
   // posedge | negedge | edge | edge_control_specifier
5408

5409
   BEGIN("timing check event control");
10✔
5410

5411
   one_of(tPOSEDGE, tNEGEDGE, tEDGE);
5✔
5412
}
5✔
5413

5414
static void p_scalar_timing_check_condition(void)
4✔
5415
{
5416
   //    expression
5417
   // | ~ expression
5418
   // | expression == scalar_constant
5419
   // | expression === scalar_constant
5420
   // | expression != scalar_constant
5421
   // | expression !== scalar_constant
5422

5423
   BEGIN("scalar timing check condition")
8✔
5424

5425
   p_expression();
4✔
5426
}
4✔
5427

5428
static void p_timing_check_condition(void)
4✔
5429
{
5430
   //     scalar_timing_check_condition
5431
   // | ( scalar_timing_check_condition )
5432

5433
   BEGIN("timing check condition");
8✔
5434

5435
   if (optional(tLPAREN)) {
4✔
5436
      p_scalar_timing_check_condition();
1✔
5437
      consume(tRPAREN);
1✔
5438
   }
5439
   else
5440
      p_scalar_timing_check_condition();
3✔
5441
}
4✔
5442

5443
static vlog_node_t p_timing_check_event(void)
20✔
5444
{
5445
   // [ timing_check_event_control ] specify_terminal_descriptor
5446
   //    [ &&& timing_check_condition ]
5447

5448
   BEGIN("timing check event");
20✔
5449

5450
   if (scan(tEDGE, tPOSEDGE, tNEGEDGE))
20✔
5451
      p_timing_check_event_control();
4✔
5452

5453
   (void)p_specify_terminal_descriptor();
20✔
5454

5455
   if (optional(tTRPLAMP))
20✔
5456
      p_timing_check_condition();
4✔
5457

5458
   return NULL;
20✔
5459
}
5460

5461
static vlog_node_t p_controlled_timing_check_event(void)
1✔
5462
{
5463
   // timing_check_event_control specify_terminal_descriptor
5464
   //    [ &&& timing_check_condition ]
5465

5466
   BEGIN("controlled timing check event");
1✔
5467

5468
   p_timing_check_event_control();
1✔
5469

5470
   (void)p_specify_terminal_descriptor();
1✔
5471

5472
   if (optional(tTRPLAMP))
1✔
UNCOV
5473
      p_timing_check_condition();
×
5474

5475
   return NULL;
1✔
5476
}
5477

5478
static vlog_node_t p_setup_or_hold_timing_check(void)
6✔
5479
{
5480
   // $setup ( data_event , reference_event , timing_check_limit
5481
   //   [ , [ notifier ] ] ) ;
5482
   //
5483
   // $hold ( reference_event , data_event , timing_check_limit
5484
   //   [ , [ notifier ] ] ) ;
5485

5486
   BEGIN("setup/hold timing check");
6✔
5487

5488
   one_of(tDLRSETUP, tDLRHOLD);
6✔
5489
   consume(tLPAREN);
6✔
5490

5491
   (void)p_timing_check_event();
6✔
5492

5493
   consume(tCOMMA);
6✔
5494

5495
   (void)p_timing_check_event();
6✔
5496

5497
   consume(tCOMMA);
6✔
5498

5499
   (void)p_expression();
6✔
5500

5501
   if (optional(tCOMMA)) {
6✔
5502
      if (peek() == tID)
4✔
5503
         p_identifier();
2✔
5504
   }
5505

5506
   consume(tRPAREN);
6✔
5507
   consume(tSEMI);
6✔
5508

5509
   return NULL;
6✔
5510
}
5511

5512
static vlog_node_t p_recovery_or_removal_timing_check(void)
2✔
5513
{
5514
   // $recovery ( reference_event , data_event , timing_check_limit
5515
   //   [ , [ notifier ] ] ) ;
5516
   //
5517
   // $removal ( reference_event , data_event , timing_check_limit
5518
   //   [ , [ notifier ] ] ) ;
5519

5520
   BEGIN("recovery/removal timing check");
2✔
5521

5522
   one_of(tDLRRECOVERY, tDLRREMOVAL);
2✔
5523
   consume(tLPAREN);
2✔
5524

5525
   (void)p_timing_check_event();
2✔
5526

5527
   consume(tCOMMA);
2✔
5528

5529
   (void)p_timing_check_event();
2✔
5530

5531
   consume(tCOMMA);
2✔
5532

5533
   (void)p_expression();
2✔
5534

5535
   if (optional(tCOMMA)) {
2✔
UNCOV
5536
      if (peek() == tID)
×
UNCOV
5537
         p_identifier();
×
5538
   }
5539

5540
   consume(tRPAREN);
2✔
5541
   consume(tSEMI);
2✔
5542

5543
   return NULL;
2✔
5544
}
5545

5546
static vlog_node_t p_width_timing_check(void)
1✔
5547
{
5548
   // $width ( controlled_reference_event , timing_check_limit , threshold
5549
   //   [ , [ notifier ] ] ) ;
5550

5551
   BEGIN("width timing check");
1✔
5552

5553
   consume(tDLRWIDTH);
1✔
5554
   consume(tLPAREN);
1✔
5555

5556
   (void)p_controlled_timing_check_event();
1✔
5557

5558
   consume(tCOMMA);
1✔
5559

5560
   (void)p_expression();
1✔
5561

5562
   consume(tCOMMA);
1✔
5563

5564
   (void)p_constant_expression();
1✔
5565

5566
   if (optional(tCOMMA)) {
1✔
UNCOV
5567
      if (peek() == tID)
×
UNCOV
5568
         p_identifier();
×
5569
   }
5570

5571
   consume(tRPAREN);
1✔
5572
   consume(tSEMI);
1✔
5573

5574
   return NULL;
1✔
5575
}
5576

5577
static vlog_node_t p_delayed_data_or_reference(void)
2✔
5578
{
5579
   // terminal_identifier
5580
   //   | terminal_identifier [ constant_mintypmax_expression ]
5581

5582
   BEGIN("delayed data/reference");
2✔
5583

5584
   p_identifier();
2✔
5585

5586
   return NULL;
2✔
5587
}
5588

5589
static vlog_node_t p_setuphold_or_recrem_timing_check(void)
2✔
5590
{
5591
   // $setuphold ( reference_event , data_event , timing_check_limit ,
5592
   //    timing_check_limit [ , [ notifier ] [ , [ timestamp_condition ]
5593
   //    [ , [ timecheck_condition ] [ , [ delayed_reference ]
5594
   //    [ , [ delayed_data ] ] ] ] ] ] ) ;
5595

5596
   BEGIN("setuphold/recrem timing check");
2✔
5597

5598
   one_of(tDLRSETUPHOLD, tDLRRECREM);
2✔
5599
   consume(tLPAREN);
2✔
5600

5601
   (void)p_timing_check_event();
2✔
5602

5603
   consume(tCOMMA);
2✔
5604

5605
   (void)p_timing_check_event();
2✔
5606

5607
   consume(tCOMMA);
2✔
5608

5609
   (void)p_expression();
2✔
5610

5611
   consume(tCOMMA);
2✔
5612

5613
   (void)p_expression();
2✔
5614

5615
   if (optional(tCOMMA)) {
2✔
5616
      if (peek() == tID)
2✔
5617
         p_identifier(); // notifier
2✔
5618

5619
      if (optional(tCOMMA)) {
2✔
5620
         if (not_at_token(tCOMMA, tRPAREN))
2✔
UNCOV
5621
            (void)p_mintypmax_expression();  // timestamp_condition
×
5622

5623
         if (optional(tCOMMA)) {
2✔
5624
            if (not_at_token(tCOMMA, tRPAREN))
2✔
UNCOV
5625
               (void)p_mintypmax_expression();  // timecheck_condition
×
5626

5627
            if (optional(tCOMMA)) {
2✔
5628
               if (not_at_token(tCOMMA, tRPAREN))
2✔
5629
                  p_delayed_data_or_reference();  // delayed_reference
1✔
5630

5631
               if (optional(tCOMMA)) {
2✔
5632
                  if (not_at_token(tCOMMA, tRPAREN))
2✔
5633
                     p_delayed_data_or_reference();  // delayed_data
1✔
5634
               }
5635
            }
5636
         }
5637
      }
5638
   }
5639

5640
   consume(tRPAREN);
2✔
5641
   consume(tSEMI);
2✔
5642

5643
   return NULL;
2✔
5644
}
5645

5646
static vlog_node_t p_system_timing_check(void)
11✔
5647
{
5648
   // $setup_timing_check | $hold_timing_check | $setuphold_timing_check
5649
   //   | $recovery_timing_check | $removal_timing_check | $recrem_timing_check
5650
   //   | $skew_timing_check | $timeskew_timing_check | $fullskew_timing_check
5651
   //   | $period_timing_check | $width_timing_check | $nochange_timing_check
5652

5653
   BEGIN("system timing check");
22✔
5654

5655
   switch (peek()) {
11✔
5656
   case tDLRSETUP:
6✔
5657
   case tDLRHOLD:
5658
      return p_setup_or_hold_timing_check();
6✔
5659
   case tDLRRECOVERY:
2✔
5660
   case tDLRREMOVAL:
5661
      return p_recovery_or_removal_timing_check();
2✔
5662
   case tDLRWIDTH:
1✔
5663
      return p_width_timing_check();
1✔
5664
   case tDLRSETUPHOLD:
2✔
5665
   case tDLRRECREM:
5666
      return p_setuphold_or_recrem_timing_check();
2✔
UNCOV
5667
   default:
×
5668
      should_not_reach_here();
5669
   }
5670
}
5671

5672
static vlog_node_t p_specparam_assignment(void)
2✔
5673
{
5674
   // specparam_identifier = constant_mintypmax_expression
5675
   //    | pulse_control_specparam
5676

5677
   BEGIN("specparam assignment");
2✔
5678

5679
   vlog_node_t v = vlog_new(V_SPECPARAM);
2✔
5680
   vlog_set_ident(v, p_identifier());
2✔
5681

5682
   consume(tEQ);
2✔
5683

5684
   vlog_set_value(v, p_constant_mintypmax_expression());
2✔
5685

5686
   vlog_set_loc(v, CURRENT_LOC);
2✔
5687
   vlog_symtab_put(symtab, v);
2✔
5688
   return v;
2✔
5689
}
5690

5691
static void p_list_of_specparam_assignments(vlog_node_t parent)
2✔
5692
{
5693
   // specparam_assignment { , specparam_assignment }
5694

5695
   BEGIN("list of specparam assignments");
4✔
5696

5697
   do {
2✔
5698
      vlog_add_decl(parent, p_specparam_assignment());
2✔
5699
   } while (optional(tCOMMA));
2✔
5700
}
2✔
5701

5702
static void p_specparam_declaration(vlog_node_t parent)
2✔
5703
{
5704
   // specparam [ packed_dimension ] list_of_specparam_assignments ;
5705

5706
   BEGIN("specparam declaration");
4✔
5707

5708
   consume(tSPECPARAM);
2✔
5709

5710
   if (peek() == tLSQUARE)
2✔
5711
      (void)p_packed_dimension();
1✔
5712

5713
   p_list_of_specparam_assignments(parent);
2✔
5714

5715
   consume(tSEMI);
2✔
5716
}
2✔
5717

5718
static void p_specify_item(vlog_node_t parent)
30✔
5719
{
5720
   // specparam_declaration | pulsestyle_declaration | showcancelled_declaration
5721
   //   | path_declaration | system_timing_check
5722

5723
   BEGIN("specify item");
60✔
5724

5725
   switch (peek()) {
30✔
5726
   case tSPECPARAM:
2✔
5727
      p_specparam_declaration(parent);
2✔
5728
      break;
2✔
5729
   case tLPAREN:
17✔
5730
   case tIF:
5731
   case tIFNONE:
5732
      (void)p_path_declaration();
17✔
5733
      break;
17✔
5734
   case tDLRSETUP:
11✔
5735
   case tDLRHOLD:
5736
   case tDLRRECOVERY:
5737
   case tDLRREMOVAL:
5738
   case tDLRSETUPHOLD:
5739
   case tDLRRECREM:
5740
   case tDLRWIDTH:
5741
      (void)p_system_timing_check();
11✔
5742
      break;
11✔
UNCOV
5743
   default:
×
UNCOV
5744
      one_of(tSPECPARAM, tLPAREN, tIF, tIFNONE, tDLRSETUP, tDLRHOLD,
×
5745
             tDLRRECOVERY, tDLRREMOVAL, tDLRSETUPHOLD, tDLRRECREM,
5746
             tDLRWIDTH);
5747
   }
5748
}
30✔
5749

5750
static vlog_node_t p_specify_block(void)
1✔
5751
{
5752
   // specify { specify_item } endspecify
5753

5754
   BEGIN("specify block");
1✔
5755

5756
   consume(tSPECIFY);
1✔
5757

5758
   vlog_node_t v = vlog_new(V_SPECIFY);
1✔
5759
   vlog_set_loc(v, CURRENT_LOC);
1✔
5760

5761
   vlog_symtab_push(symtab, v);
1✔
5762

5763
   while (not_at_token(tENDSPECIFY))
31✔
5764
      p_specify_item(v);
30✔
5765

5766
   vlog_symtab_pop(symtab);
1✔
5767

5768
   consume(tENDSPECIFY);
1✔
5769

5770
   vlog_set_loc(v, CURRENT_LOC);
1✔
5771
   return v;
1✔
5772
}
5773

5774
static vlog_node_t p_ordered_port_connection(void)
89✔
5775
{
5776
   // { attribute_instance } [ expression ]
5777

5778
   BEGIN("ordered port connection");
89✔
5779

5780
   optional_attributes();
89✔
5781

5782
   vlog_node_t v = vlog_new(V_PORT_CONN);
89✔
5783

5784
   if (not_at_token(tCOMMA, tRPAREN))
89✔
5785
      vlog_set_value(v, p_expression());
89✔
5786

5787
   vlog_set_loc(v, CURRENT_LOC);
89✔
5788
   return v;
89✔
5789
}
5790

5791
static vlog_node_t p_named_port_connection(void)
25✔
5792
{
5793
   // { attribute_instance } . port_identifier [ ( [ expression ] ) ]
5794
   //    | { attribute_instance } .*
5795

5796
   BEGIN("named port connection");
25✔
5797

5798
   optional_attributes();
25✔
5799

5800
   vlog_node_t v = vlog_new(V_PORT_CONN);
25✔
5801

5802
   consume(tDOT);
25✔
5803

5804
   vlog_set_ident(v, p_identifier());
25✔
5805

5806
   if (optional(tLPAREN)) {
25✔
5807

5808
      if (peek() != tRPAREN)
25✔
5809
         vlog_set_value(v, p_expression());
25✔
5810

5811
      consume(tRPAREN);
25✔
5812
   }
5813

5814
   vlog_set_loc(v, CURRENT_LOC);
25✔
5815
   return v;
25✔
5816
}
5817

5818
static void p_list_of_port_connections(vlog_node_t inst)
63✔
5819
{
5820
   // ordered_port_connection { , ordered_port_connection }
5821
   //   | named_port_connection { , named_port_connection }
5822

5823
   BEGIN("list of port connections");
126✔
5824

5825
   vlog_symtab_set_implicit(symtab, implicit_kind);
63✔
5826

5827
   do {
114✔
5828
      skip_over_attributes();
114✔
5829

5830
      if (peek() == tDOT)
114✔
5831
         vlog_add_param(inst, p_named_port_connection());
25✔
5832
      else
5833
         vlog_add_param(inst, p_ordered_port_connection());
89✔
5834
   } while (optional(tCOMMA));
114✔
5835

5836
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
63✔
5837
}
63✔
5838

5839
static vlog_node_t p_hierarchical_instance(void)
70✔
5840
{
5841
   // name_of_instance ( [ list_of_port_connections ] )
5842

5843
   BEGIN("hierarchical instance");
70✔
5844

5845
   vlog_node_t v = vlog_new(V_MOD_INST);
70✔
5846
   vlog_set_ident(v, p_identifier());
70✔
5847

5848
   consume(tLPAREN);
70✔
5849

5850
   if (peek() != tRPAREN)
70✔
5851
      p_list_of_port_connections(v);
62✔
5852

5853
   consume(tRPAREN);
70✔
5854

5855
   vlog_set_loc(v, CURRENT_LOC);
70✔
5856
   vlog_symtab_put(symtab, v);
70✔
5857
   return v;
70✔
5858
}
5859

5860
static vlog_node_t p_udp_instance(void)
1✔
5861
{
5862
   // [ name_of_instance ] ( output_terminal , input_terminal
5863
   //   { , input_terminal } )
5864

5865
   BEGIN("udp instance");
1✔
5866

5867
   vlog_node_t v = vlog_new(V_MOD_INST);
1✔
5868
   if (peek() == tID)
1✔
UNCOV
5869
      vlog_set_ident(v, p_identifier());
×
5870
   else
5871
      vlog_set_ident(v, ident_uniq("$unnamed"));
1✔
5872

5873
   consume(tLPAREN);
1✔
5874

5875
   p_list_of_port_connections(v);
1✔
5876

5877
   consume(tRPAREN);
1✔
5878

5879
   vlog_set_loc(v, CURRENT_LOC);
1✔
5880
   return v;
1✔
5881
}
5882

5883
static vlog_node_t p_param_expression(void)
37✔
5884
{
5885
   // mintypmax_expression | data_type | $
5886

5887
   BEGIN("param expression");
74✔
5888

5889
   return p_expression();   // TODO
37✔
5890
}
5891

5892
static vlog_node_t p_named_parameter_assignment(void)
5✔
5893
{
5894
   // . parameter_identifier ( [ param_expression ] )
5895

5896
   BEGIN("named parameter assignment");
5✔
5897

5898
   consume(tDOT);
5✔
5899

5900
   vlog_node_t v = vlog_new(V_PARAM_ASSIGN);
5✔
5901
   vlog_set_ident(v, p_identifier());
5✔
5902

5903
   consume(tLPAREN);
5✔
5904

5905
   if (peek() != tRPAREN)
5✔
5906
      vlog_set_value(v, p_param_expression());
5✔
5907

5908
   consume(tRPAREN);
5✔
5909

5910
   vlog_set_loc(v, CURRENT_LOC);
5✔
5911
   return v;
5✔
5912
}
5913

5914
static vlog_node_t p_ordered_parameter_assignment(void)
32✔
5915
{
5916
   // param_expression
5917

5918
   BEGIN("ordered parameter assignment");
32✔
5919

5920
   vlog_node_t v = vlog_new(V_PARAM_ASSIGN);
32✔
5921
   vlog_set_value(v, p_param_expression());
32✔
5922

5923
   vlog_set_loc(v, CURRENT_LOC);
32✔
5924
   return v;
32✔
5925
}
5926

5927
static void p_list_of_parameter_assignments(vlog_node_t inst)
35✔
5928
{
5929
   // ordered_parameter_assignment { , ordered_parameter_assignment }
5930
   //   | named_parameter_assignment { , named_parameter_assignment }
5931

5932
   BEGIN("list of parameter assignments");
70✔
5933

5934
   do {
37✔
5935
      if (peek() == tDOT)
37✔
5936
         vlog_add_param(inst, p_named_parameter_assignment());
5✔
5937
      else
5938
         vlog_add_param(inst, p_ordered_parameter_assignment());
32✔
5939
   } while (optional(tCOMMA));
37✔
5940
}
35✔
5941

5942
static void p_parameter_value_assignment(vlog_node_t inst)
35✔
5943
{
5944
   // # ( [ list_of_parameter_assignments ] )
5945

5946
   BEGIN("parameter value assignment");
70✔
5947

5948
   consume(tHASH);
35✔
5949
   consume(tLPAREN);
35✔
5950

5951
   if (peek() != tRPAREN)
35✔
5952
      p_list_of_parameter_assignments(inst);
35✔
5953

5954
   consume(tRPAREN);
35✔
5955
}
35✔
5956

5957
static void p_module_or_udp_instantiation(vlog_node_t mod)
69✔
5958
{
5959
   // module_identifier [ parameter_value_assignment ] hierarchical_instance
5960
   //   { , hierarchical_instance } ;
5961
   //
5962
   // udp_identifier [ drive_strength ] [ delay2 ] udp_instance
5963
   //   { , udp_instance } ;
5964

5965
   BEGIN("module instantiation");
138✔
5966

5967
   vlog_node_t v = vlog_new(V_INST_LIST);
69✔
5968
   vlog_set_ident(v, p_identifier());
69✔
5969

5970
   if (peek() == tHASH)
69✔
5971
      p_parameter_value_assignment(v);
35✔
5972

5973
   do {
71✔
5974
      if (peek() == tLPAREN)
71✔
5975
         vlog_add_stmt(v, p_udp_instance());
1✔
5976
      else
5977
         vlog_add_stmt(v, p_hierarchical_instance());
70✔
5978
   } while (optional(tCOMMA));
71✔
5979

5980
   consume(tSEMI);
69✔
5981

5982
   vlog_set_loc(v, CURRENT_LOC);
69✔
5983

5984
   vlog_add_stmt(mod, v);
69✔
5985
}
69✔
5986

5987
static vlog_node_t p_defparam_assignment(void)
3✔
5988
{
5989
   // hierarchical_parameter_identifier = constant_mintypmax_expression
5990

5991
   BEGIN("defparam assignment");
3✔
5992

5993
   vlog_node_t v = vlog_new(V_DEFPARAM);
3✔
5994
   vlog_set_target(v, p_hierarchical_identifier(NULL));
3✔
5995

5996
   consume(tEQ);
3✔
5997

5998
   vlog_set_value(v, p_constant_mintypmax_expression());
3✔
5999

6000
   vlog_set_loc(v, CURRENT_LOC);
3✔
6001
   return v;
3✔
6002
}
6003

6004
static void p_list_of_defparam_assignments(vlog_node_t parent)
3✔
6005
{
6006
   // defparam_assignment { , defparam_assignment }
6007

6008
   BEGIN("list of defparam assignments");
6✔
6009

6010
   do {
3✔
6011
      vlog_add_stmt(parent, p_defparam_assignment());
3✔
6012
   } while (optional(tCOMMA));
3✔
6013
}
3✔
6014

6015
static void p_parameter_override(vlog_node_t parent)
3✔
6016
{
6017
   // defparam list_of_defparam_assignments ;
6018

6019
   BEGIN("parameter override");
6✔
6020

6021
   consume(tDEFPARAM);
3✔
6022

6023
   p_list_of_defparam_assignments(parent);
3✔
6024

6025
   consume(tSEMI);
3✔
6026
}
3✔
6027

6028
static void p_module_or_generate_item(vlog_node_t mod)
1,847✔
6029
{
6030
   // { attribute_instance } parameter_override
6031
   //   | { attribute_instance } gate_instantiation
6032
   //   | { attribute_instance } udp_instantiation
6033
   //   | { attribute_instance } module_instantiation
6034
   //   | { attribute_instance } module_common_item
6035

6036
   BEGIN("module or generate item");
3,694✔
6037

6038
   optional_attributes();
1,847✔
6039

6040
   switch (peek()) {
1,847✔
6041
   case tALWAYS:
1,716✔
6042
   case tALWAYSCOMB:
6043
   case tALWAYSFF:
6044
   case tALWAYSLATCH:
6045
   case tWIRE:
6046
   case tUWIRE:
6047
   case tSUPPLY0:
6048
   case tSUPPLY1:
6049
   case tTRI:
6050
   case tTRI0:
6051
   case tTRI1:
6052
   case tTRIAND:
6053
   case tTRIOR:
6054
   case tTRIREG:
6055
   case tWAND:
6056
   case tWOR:
6057
   case tINTERCONNECT:
6058
   case tREG:
6059
   case tSTRUCT:
6060
   case tUNION:
6061
   case tASSIGN:
6062
   case tINITIAL:
6063
   case tTYPEDEF:
6064
   case tENUM:
6065
   case tSVINT:
6066
   case tINTEGER:
6067
   case tSVREAL:
6068
   case tSHORTREAL:
6069
   case tREALTIME:
6070
   case tTIME:
6071
   case tTASK:
6072
   case tFUNCTION:
6073
   case tLOCALPARAM:
6074
   case tPARAMETER:
6075
   case tIF:
6076
   case tFOR:
6077
   case tEVENT:
6078
   case tGENVAR:
6079
   case tVAR:
6080
   case tLOGIC:
6081
   case tBIT:
6082
   case tSHORTINT:
6083
   case tLONGINT:
6084
   case tBYTE:
6085
   case tSTRINGK:
6086
   case tIMPORT:
6087
      p_module_common_item(mod);
1,716✔
6088
      break;
1,716✔
6089
   case tPULLDOWN:
49✔
6090
   case tPULLUP:
6091
   case tAND:
6092
   case tNAND:
6093
   case tOR:
6094
   case tNOR:
6095
   case tXOR:
6096
   case tXNOR:
6097
   case tNOT:
6098
   case tBUF:
6099
   case tBUFIF0:
6100
   case tBUFIF1:
6101
   case tNOTIF0:
6102
   case tNOTIF1:
6103
   case tTRAN:
6104
   case tTRANIF0:
6105
   case tTRANIF1:
6106
   case tRTRAN:
6107
   case tRTRANIF0:
6108
   case tRTRANIF1:
6109
      p_gate_instantiation(mod);
49✔
6110
      break;
49✔
6111
   case tDEFPARAM:
3✔
6112
      p_parameter_override(mod);
3✔
6113
      break;
3✔
6114
   case tID:
79✔
6115
      {
6116
         vlog_node_t ref = peek_reference();
79✔
6117
         if (ref == NULL)
79✔
6118
            p_module_or_udp_instantiation(mod);
69✔
6119
         else
6120
            p_module_common_item(mod);
10✔
6121
      }
6122
      break;
UNCOV
6123
   default:
×
UNCOV
6124
      expect(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
×
6125
             tSUPPLY0, tSUPPLY1, tTRI,  tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
6126
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tASSIGN,
6127
             tINITIAL, tTYPEDEF, tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL,
6128
             tREALTIME, tTIME, tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER, tIF,
6129
             tFOR, tEVENT, tGENVAR, tVAR, tLOGIC, tBIT, tSHORTINT, tLONGINT,
6130
             tBYTE, tSTRINGK, tIMPORT, tPULLDOWN, tPULLUP, tID, tAND, tNAND,
6131
             tOR, tNOR, tXOR, tXNOR, tNOT, tBUF, tBUFIF0, tBUFIF1, tNOTIF0,
6132
             tNOTIF1, tDEFPARAM, tID);
UNCOV
6133
      drop_tokens_until(tSEMI);
×
6134
   }
6135
}
1,847✔
6136

6137
static void p_generate_region(vlog_node_t mod)
8✔
6138
{
6139
   // generate { generate_item } endgenerate
6140

6141
   BEGIN("generate region");
16✔
6142

6143
   // Has no real meaning in System Verilog
6144

6145
   // TODO: generate regions do not nest so check mod is V_MODULE
6146

6147
   consume(tGENERATE);
8✔
6148

6149
   if (optional(tBEGIN)) {
8✔
6150
      // This is non-standard but seen in some legacy code
6151
      consume(tCOLON);
1✔
6152

6153
      vlog_node_t b = vlog_new(V_BLOCK);
1✔
6154
      vlog_set_ident(b, p_identifier());
1✔
6155

6156
      while (not_at_token(tEND))
1✔
UNCOV
6157
         p_generate_item(b);
×
6158

6159
      consume(tEND);
1✔
6160

6161
      vlog_set_loc(b, CURRENT_LOC);
1✔
6162
      vlog_add_stmt(mod, b);
1✔
6163
   }
6164
   else {
6165
      while (not_at_token(tENDGENERATE))
14✔
6166
         p_generate_item(mod);
7✔
6167
   }
6168

6169
   consume(tENDGENERATE);
8✔
6170
}
8✔
6171

6172
static void p_non_port_module_item(vlog_node_t mod)
1,774✔
6173
{
6174
   // generate_region | module_or_generate_item | specify_block
6175
   //   | { attribute_instance } specparam_declaration | program_declaration
6176
   //   | module_declaration | interface_declaration | timeunits_declaration
6177

6178
   BEGIN("non-port module item");
3,548✔
6179

6180
   switch (peek()) {
1,774✔
6181
   case tALWAYS:
1,763✔
6182
   case tALWAYSCOMB:
6183
   case tALWAYSFF:
6184
   case tALWAYSLATCH:
6185
   case tWIRE:
6186
   case tUWIRE:
6187
   case tSUPPLY0:
6188
   case tSUPPLY1:
6189
   case tTRI:
6190
   case tTRI0:
6191
   case tTRI1:
6192
   case tTRIAND:
6193
   case tTRIOR:
6194
   case tTRIREG:
6195
   case tWAND:
6196
   case tWOR:
6197
   case tINTERCONNECT:
6198
   case tREG:
6199
   case tSTRUCT:
6200
   case tUNION:
6201
   case tASSIGN:
6202
   case tINITIAL:
6203
   case tPULLDOWN:
6204
   case tPULLUP:
6205
   case tID:
6206
   case tATTRBEGIN:
6207
   case tAND:
6208
   case tNAND:
6209
   case tOR:
6210
   case tNOR:
6211
   case tXOR:
6212
   case tXNOR:
6213
   case tNOT:
6214
   case tBUF:
6215
   case tBUFIF0:
6216
   case tBUFIF1:
6217
   case tNOTIF0:
6218
   case tNOTIF1:
6219
   case tTRAN:
6220
   case tTRANIF0:
6221
   case tTRANIF1:
6222
   case tRTRAN:
6223
   case tRTRANIF0:
6224
   case tRTRANIF1:
6225
   case tTYPEDEF:
6226
   case tENUM:
6227
   case tSVINT:
6228
   case tINTEGER:
6229
   case tSVREAL:
6230
   case tSHORTREAL:
6231
   case tREALTIME:
6232
   case tTIME:
6233
   case tTASK:
6234
   case tFUNCTION:
6235
   case tLOCALPARAM:
6236
   case tPARAMETER:
6237
   case tEVENT:
6238
   case tIF:
6239
   case tFOR:
6240
   case tGENVAR:
6241
   case tVAR:
6242
   case tLOGIC:
6243
   case tBIT:
6244
   case tSHORTINT:
6245
   case tLONGINT:
6246
   case tBYTE:
6247
   case tSTRINGK:
6248
   case tIMPORT:
6249
   case tDEFPARAM:
6250
      p_module_or_generate_item(mod);
1,763✔
6251
      break;
1,763✔
6252
   case tSPECIFY:
1✔
6253
      vlog_add_stmt(mod, p_specify_block());
1✔
6254
      break;
1✔
6255
   case tGENERATE:
8✔
6256
      p_generate_region(mod);
8✔
6257
      break;
8✔
6258
   default:
2✔
6259
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
2✔
6260
             tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
6261
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tASSIGN,
6262
             tPULLDOWN, tPULLUP, tID, tATTRBEGIN, tAND, tNAND, tOR, tNOR, tXOR,
6263
             tXNOR, tNOT, tBUF, tBUFIF0, tBUFIF1, tNOTIF0, tNOTIF1, tTYPEDEF,
6264
             tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTIME,
6265
             tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER, tEVENT, tIF, tFOR,
6266
             tGENVAR, tVAR, tLOGIC, tBIT, tSHORTINT, tLONGINT, tBYTE, tSTRINGK,
6267
             tIMPORT, tDEFPARAM, tSPECIFY, tGENERATE);
6268
      drop_tokens_until(tSEMI);
2✔
6269
   }
6270
}
1,774✔
6271

6272
static void p_module_item(vlog_node_t mod)
1,965✔
6273
{
6274
   // port_declaration ; | non_port_module_item
6275

6276
   BEGIN("module item");
3,930✔
6277

6278
   skip_over_attributes();
1,965✔
6279

6280
   if (scan(tINOUT, tINPUT, tOUTPUT)) {
1,965✔
6281
      p_port_declaration(mod);
191✔
6282
      consume(tSEMI);
191✔
6283
   }
6284
   else
6285
      p_non_port_module_item(mod);
1,774✔
6286
}
1,965✔
6287

6288
static void p_ansi_port_declaration(vlog_node_t mod, v_port_kind_t *kind,
67✔
6289
                                    vlog_node_t *dt)
6290
{
6291
   // [ net_port_header | interface_port_header ] port_identifier
6292
   //     { unpacked_dimension } [ = constant_expression ]
6293
   // | [ variable_port_header ] port_identifier { variable_dimension }
6294
   //     [ = constant_expression ]
6295
   // | [ port_direction ] . port_identifier ( [ expression ] )
6296

6297
   BEGIN("ANSI port declaration");
134✔
6298

6299
   if (peek() != tID)
67✔
6300
      p_net_port_header(kind, dt);
47✔
6301
   else if (*dt == NULL)
20✔
UNCOV
6302
      *dt = implicit_type();
×
6303

6304
   ident_t id, ext;
67✔
6305
   p_external_identifier(&id, &ext);
67✔
6306

6307
   vlog_node_t v = vlog_new(V_PORT_DECL);
67✔
6308
   vlog_set_subkind(v, *kind);
67✔
6309
   vlog_set_ident(v, id);
67✔
6310
   vlog_set_ident2(v, ext);
67✔
6311
   vlog_set_type(v, *dt);
67✔
6312
   vlog_set_loc(v, &state.last_loc);
67✔
6313

6314
   vlog_add_decl(mod, v);
67✔
6315
   vlog_symtab_put(symtab, v);
67✔
6316

6317
   vlog_node_t ref = vlog_new(V_REF);
67✔
6318
   vlog_set_loc(ref, CURRENT_LOC);
67✔
6319
   vlog_set_ident(ref, id);
67✔
6320
   vlog_set_ref(ref, v);
67✔
6321

6322
   vlog_add_port(mod, ref);
67✔
6323
}
67✔
6324

6325
static void p_list_of_port_declarations(vlog_node_t mod)
54✔
6326
{
6327
   // ( [ { attribute_instance } ansi_port_declaration
6328
   //   { , { attribute_instance } ansi_port_declaration } ] )
6329

6330
   BEGIN("list of port declarations");
108✔
6331

6332
   consume(tLPAREN);
54✔
6333

6334
   if (peek() != tRPAREN) {
54✔
6335
      v_port_kind_t kind = V_PORT_INPUT;
21✔
6336
      vlog_node_t dt = NULL;
21✔
6337
      do {
67✔
6338
         optional_attributes();
67✔
6339
         p_ansi_port_declaration(mod, &kind, &dt);
67✔
6340
      } while (optional(tCOMMA));
67✔
6341
   }
6342

6343
   consume(tRPAREN);
54✔
6344
}
54✔
6345

6346
static void p_parameter_port_declaration(vlog_node_t mod)
19✔
6347
{
6348
   // parameter_declaration
6349
   //    | local_parameter_declaration
6350
   //    | data_type list_of_param_assignments
6351
   //    | type list_of_type_assignments
6352

6353
   BEGIN("parameter port declaration");
38✔
6354

6355
   switch (peek()) {
19✔
6356
   case tPARAMETER:
14✔
6357
      p_parameter_declaration(mod);
14✔
6358
      break;
14✔
6359
   case tLOCALPARAM:
4✔
6360
      p_local_parameter_declaration(mod);
4✔
6361
      break;
4✔
6362
   default:
1✔
6363
      // TODO: Add parsing of "type" declarations example #(type T = bit)
6364
      {
6365
         vlog_node_t datatype = p_data_type();
1✔
6366
         p_list_of_param_assignments(mod, datatype, V_PARAM_DECL);
1✔
6367
      }
6368
      break;
1✔
6369
   }
6370
}
19✔
6371

6372
static void p_parameter_port_list(vlog_node_t mod)
8✔
6373
{
6374
   // # ( list_of_param_assignments { , parameter_port_declaration } )
6375
   //    | # ( parameter_port_declaration { , parameter_port_declaration } )
6376
   //    | # ( )
6377

6378
   BEGIN("parameter port list");
16✔
6379

6380
   consume(tHASH);
8✔
6381
   consume(tLPAREN);
8✔
6382

6383
   if (peek() != tRPAREN) {
8✔
6384
      do {
20✔
6385
         if (peek() == tID)
20✔
6386
            p_list_of_param_assignments(mod, NULL, V_PARAM_DECL);
1✔
6387
         else
6388
            p_parameter_port_declaration(mod);
19✔
6389
      } while(optional(tCOMMA));
20✔
6390
   }
6391

6392
   consume(tRPAREN);
8✔
6393
}
8✔
6394

6395
static void p_module_ansi_header(vlog_node_t mod)
318✔
6396
{
6397
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
6398
   //    { package_import_declaration } [ parameter_port_list ]
6399
   ///   [ list_of_port_declarations ] ;
6400

6401
   EXTEND("module ANSI header");
636✔
6402

6403
   if (peek() == tHASH) {
318✔
6404
      p_parameter_port_list(mod);
8✔
6405
      param_kind = V_LOCALPARAM;
8✔
6406
   }
6407

6408
   if (peek() == tLPAREN)
318✔
6409
      p_list_of_port_declarations(mod);
54✔
6410

6411
   consume(tSEMI);
318✔
6412

6413
   vlog_set_loc(mod, CURRENT_LOC);
318✔
6414
}
318✔
6415

6416
static vlog_node_t p_port_reference(void)
214✔
6417
{
6418
   // port_identifier constant_select
6419

6420
   BEGIN("port reference");
214✔
6421

6422
   vlog_node_t v = vlog_new(V_REF);
214✔
6423
   vlog_set_ident(v, p_identifier());
214✔
6424
   vlog_set_loc(v, CURRENT_LOC);
214✔
6425
   return v;
214✔
6426
}
6427

6428
static vlog_node_t p_port_expression(void)
214✔
6429
{
6430
   // port_reference | { port_reference { , port_reference } }
6431

6432
   BEGIN("port expression");
428✔
6433

6434
   return p_port_reference();
214✔
6435
}
6436

6437
static vlog_node_t p_port(void)
214✔
6438
{
6439
   // [ port_expression ] | . port_identifier ( [ port_expression ] )
6440

6441
   BEGIN("port");
428✔
6442

6443
   return p_port_expression();
214✔
6444
}
6445

6446
static void p_list_of_ports(vlog_node_t mod)
73✔
6447
{
6448
   // ( port { , port } )
6449

6450
   BEGIN("list of ports");
146✔
6451

6452
   consume(tLPAREN);
73✔
6453

6454
   do {
214✔
6455
      vlog_add_port(mod, p_port());
214✔
6456
   } while (optional(tCOMMA));
214✔
6457

6458
   consume(tRPAREN);
73✔
6459
}
73✔
6460

6461
static void p_module_nonansi_header(vlog_node_t mod)
73✔
6462
{
6463
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
6464
   //    { package_import_declaration } [ parameter_port_list ] list_of_ports ;
6465

6466
   EXTEND("module non-ANSI header");
146✔
6467

6468
   p_list_of_ports(mod);
73✔
6469

6470
   consume(tSEMI);
73✔
6471

6472
   vlog_set_loc(mod, CURRENT_LOC);
73✔
6473
}
73✔
6474

6475
static vlog_node_t p_module_declaration(void)
391✔
6476
{
6477
   // module_nonansi_header [ timeunits_declaration ] { module_item }
6478
   //      endmodule [ : module_identifier ]
6479
   //   | module_ansi_header [ timeunits_declaration ] { non_port_module_item }
6480
   //      endmodule [ : module_identifier ]
6481
   //   | { attribute_instance } module_keyword [ lifetime ] module_identifier
6482
   //      ( .* ) ; [ timeunits_declaration ] { module_item } endmodule
6483
   //      [ : module_identifier ]
6484
   //   | extern module_nonansi_header
6485
   //   | extern module_ansi_header
6486

6487
   BEGIN("module declaration");
391✔
6488

6489
   vlog_node_t mod = vlog_new(V_MODULE);
391✔
6490

6491
   optional_attributes();
391✔
6492

6493
   consume(tMODULE);
391✔
6494

6495
   ident_t id, ext;
391✔
6496
   p_external_identifier(&id, &ext);
391✔
6497
   vlog_set_ident2(mod, id);
391✔
6498

6499
   vlog_set_loc(mod, &state.last_loc);
391✔
6500

6501
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
391✔
6502
   vlog_set_ident(mod, qual);
391✔
6503

6504
   vlog_symtab_push(symtab, mod);
391✔
6505

6506
   while (peek() == tIMPORT)
391✔
UNCOV
6507
      p_package_import_declaration(mod);
×
6508

6509
   if (peek() == tLPAREN && peek_nth(2) == tID)
391✔
6510
      p_module_nonansi_header(mod);
73✔
6511
   else
6512
      p_module_ansi_header(mod);
318✔
6513

6514
   while (not_at_token(tENDMODULE))
2,356✔
6515
      p_module_item(mod);
1,965✔
6516

6517
   consume(tENDMODULE);
391✔
6518

6519
   if (optional(tCOLON)) {
391✔
6520
      ident_t name = p_identifier();
2✔
6521
      if (id != name)
2✔
6522
         error_at(&state.last_loc, "'%s' does not match module name '%s'",
1✔
6523
                  istr(name), istr(id));
6524
   }
6525

6526
   vlog_symtab_pop(symtab);
391✔
6527
   return mod;
391✔
6528
}
6529

6530
static void p_udp_port_list(vlog_node_t udp)
18✔
6531
{
6532
   // output_port_identifier , input_port_identifier { , input_port_identifier }
6533

6534
   BEGIN("UDP port list");
36✔
6535

6536
   vlog_node_t oref = vlog_new(V_REF);
18✔
6537
   vlog_set_ident(oref, p_identifier());
18✔
6538
   vlog_set_loc(oref, &state.last_loc);
18✔
6539

6540
   vlog_add_port(udp, oref);
18✔
6541

6542
   consume(tCOMMA);
18✔
6543

6544
   vlog_node_t iref = vlog_new(V_REF);
18✔
6545
   vlog_set_ident(iref, p_identifier());
18✔
6546
   vlog_set_loc(iref, &state.last_loc);
18✔
6547

6548
   vlog_add_port(udp, iref);
18✔
6549

6550
   while (optional(tCOMMA)) {
41✔
6551
      vlog_node_t iref = vlog_new(V_REF);
23✔
6552
      vlog_set_ident(iref, p_identifier());
23✔
6553
      vlog_set_loc(iref, &state.last_loc);
23✔
6554

6555
      vlog_add_port(udp, iref);
23✔
6556
   }
6557
}
18✔
6558

6559
static vlog_node_t p_udp_nonansi_declaration(void)
18✔
6560
{
6561
   // { attribute_instance } primitive udp_identifier ( udp_port_list ) ;
6562

6563
   BEGIN("UDP non-ANSI declaration");
18✔
6564

6565
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
18✔
6566

6567
   consume(tPRIMITIVE);
18✔
6568

6569
   ident_t id, ext;
18✔
6570
   p_external_identifier(&id, &ext);
18✔
6571
   vlog_set_ident2(udp, id);
18✔
6572

6573
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
18✔
6574
   vlog_set_ident(udp, qual);
18✔
6575

6576
   consume(tLPAREN);
18✔
6577

6578
   p_udp_port_list(udp);
18✔
6579

6580
   consume(tRPAREN);
18✔
6581
   consume(tSEMI);
18✔
6582

6583
   vlog_set_loc(udp, CURRENT_LOC);
18✔
6584
   return udp;
18✔
6585
}
6586

6587
static void p_list_of_udp_port_identifiers(vlog_node_t udp, v_port_kind_t kind)
19✔
6588
{
6589
   // port_identifier { , port_identifier }
6590

6591
   BEGIN("list of UDP port identifiers");
38✔
6592

6593
   do {
41✔
6594
      ident_t id, ext;
41✔
6595
      p_external_identifier(&id, &ext);
41✔
6596

6597
      vlog_node_t p = vlog_new(V_PORT_DECL);
41✔
6598
      vlog_set_subkind(p, kind);
41✔
6599
      vlog_set_ident(p, id);
41✔
6600
      vlog_set_ident2(p, ext);
41✔
6601
      vlog_set_type(p, implicit_type());
41✔
6602
      vlog_set_loc(p, &state.last_loc);
41✔
6603

6604
      vlog_add_decl(udp, p);
41✔
6605
      vlog_symtab_put(symtab, p);
41✔
6606
   } while (optional(tCOMMA));
41✔
6607
}
19✔
6608

6609
static void p_udp_output_declaration(vlog_node_t udp, bool *has_reg)
19✔
6610
{
6611
   // { attribute_instance } output port_identifier
6612
   //    | { attribute_instance } output reg port_identifier
6613
   //         [ = constant_expression ]
6614

6615
   BEGIN("UDP output declaration");
38✔
6616

6617
   consume(tOUTPUT);
19✔
6618

6619
   const bool isreg = optional(tREG);
19✔
6620

6621
   ident_t id, ext;
19✔
6622
   p_external_identifier(&id, &ext);
19✔
6623

6624
   vlog_node_t v = vlog_new(V_PORT_DECL);
19✔
6625
   vlog_set_subkind(v, V_PORT_OUTPUT);
19✔
6626
   vlog_set_ident(v, id);
19✔
6627
   vlog_set_ident2(v, ext);
19✔
6628
   vlog_set_loc(v, &state.last_loc);
19✔
6629

6630
   if (isreg) {
19✔
6631
      vlog_set_type(v, logic_type());
2✔
6632
      *has_reg = true;
2✔
6633
   }
6634
   else
6635
      vlog_set_type(v, implicit_type());
17✔
6636

6637
   vlog_add_decl(udp, v);
19✔
6638
   vlog_symtab_put(symtab, v);
19✔
6639
}
19✔
6640

6641
static void p_udp_input_declaration(vlog_node_t udp)
19✔
6642
{
6643
   // { attribute_instance } input list_of_udp_port_identifiers
6644

6645
   BEGIN("UDP input declaration");
38✔
6646

6647
   consume(tINPUT);
19✔
6648

6649
   p_list_of_udp_port_identifiers(udp, V_PORT_INPUT);
19✔
6650
}
19✔
6651

6652
static vlog_node_t p_udp_reg_declaration(void)
10✔
6653
{
6654
   // { attribute_instance } reg variable_identifier
6655

6656
   BEGIN("UDP reg declaration");
10✔
6657

6658
   consume(tREG);
10✔
6659

6660
   ident_t id = p_identifier();
10✔
6661

6662
   vlog_node_t reg = vlog_new(V_VAR_DECL);
10✔
6663
   vlog_set_loc(reg, &state.last_loc);
10✔
6664
   vlog_set_ident(reg, id);
10✔
6665
   vlog_set_type(reg, logic_type());
10✔
6666

6667
   return reg;
10✔
6668
}
6669

6670
static void p_udp_port_declaration(vlog_node_t udp, bool *has_reg)
46✔
6671
{
6672
   // udp_output_declaration ; | udp_input_declaration ; | udp_reg_declaration ;
6673

6674
   BEGIN("UDP port declaration");
92✔
6675

6676
   switch (peek()) {
46✔
6677
   case tOUTPUT:
18✔
6678
      p_udp_output_declaration(udp, has_reg);
18✔
6679
      break;
18✔
6680
   case tINPUT:
18✔
6681
      p_udp_input_declaration(udp);
18✔
6682
      break;
18✔
6683
   case tREG:
10✔
6684
      {
6685
         vlog_node_t v = p_udp_reg_declaration();
10✔
6686
         vlog_add_decl(udp, v);
10✔
6687
         vlog_symtab_put(symtab, v);
10✔
6688
         *has_reg = true;
10✔
6689
      }
6690
      break;
10✔
UNCOV
6691
   default:
×
UNCOV
6692
      one_of(tOUTPUT, tINPUT, tREG);
×
UNCOV
6693
      break;
×
6694
   }
6695

6696
   consume(tSEMI);
46✔
6697
}
46✔
6698

6699
static void p_udp_declaration_port_list(vlog_node_t udp, bool *has_reg)
1✔
6700
{
6701
   // udp_output_declaration , udp_input_declaration { , udp_input_declaration }
6702

6703
   BEGIN("UDP declaration port list");
2✔
6704

6705
   p_udp_output_declaration(udp, has_reg);
1✔
6706

6707
   consume(tCOMMA);
1✔
6708

6709
   do {
1✔
6710
      p_udp_input_declaration(udp);
1✔
6711
   } while (optional(tCOMMA));
1✔
6712

6713
   const int ndecls = vlog_decls(udp);
1✔
6714
   for (int i = 0; i < ndecls; i++) {
3✔
6715
      vlog_node_t p = vlog_decl(udp, i);
2✔
6716
      if (vlog_kind(p) != V_PORT_DECL)
2✔
UNCOV
6717
         continue;
×
6718

6719
      vlog_node_t ref = vlog_new(V_REF);
2✔
6720
      vlog_set_loc(ref, vlog_loc(p));
2✔
6721
      vlog_set_ident(ref, vlog_ident(p));
2✔
6722
      vlog_set_ref(ref, p);
2✔
6723

6724
      vlog_add_port(udp, ref);
2✔
6725
   }
6726
}
1✔
6727

6728
static vlog_node_t p_output_symbol(void)
75✔
6729
{
6730
   // 0 | 1 | x | X
6731

6732
   BEGIN("output symbol");
75✔
6733

6734
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
75✔
6735
   vlog_set_subkind(v, V_UDP_SYMBOL_OUTPUT);
75✔
6736

6737
   if (consume(tUDPLEVEL)) {
75✔
6738
      switch (state.last_lval.i64) {
75✔
6739
      case '0':
75✔
6740
      case '1':
6741
      case 'x':
6742
      case 'X':
6743
         vlog_set_ival(v, state.last_lval.i64);
75✔
6744
         break;
75✔
UNCOV
6745
      default:
×
UNCOV
6746
         parse_error(&state.last_loc, "'%c' is not a valid output symbol",
×
6747
                  (char)state.last_lval.i64);
6748
         break;
6749
      }
6750
   }
6751

6752
   vlog_set_loc(v, CURRENT_LOC);
75✔
6753
   return v;
75✔
6754
}
6755

6756
static vlog_node_t p_level_symbol(void)
337✔
6757
{
6758
   // 0 | 1 | x | X | ? | b | B
6759

6760
   BEGIN("level symbol");
337✔
6761

6762
   consume(tUDPLEVEL);
337✔
6763

6764
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
337✔
6765
   vlog_set_subkind(v, V_UDP_SYMBOL_INPUT);
337✔
6766
   vlog_set_ival(v, state.last_lval.i64);
337✔
6767

6768
   vlog_set_loc(v, CURRENT_LOC);
337✔
6769
   return v;
337✔
6770
}
6771

6772
static vlog_node_t p_next_state(void)
79✔
6773
{
6774
   // output_symbol | -
6775

6776
   BEGIN("next state");
158✔
6777

6778
   switch (peek()) {
79✔
6779
   case tMINUS:
27✔
6780
      consume(tMINUS);
27✔
6781
      break;
27✔
6782
   case tUDPLEVEL:
52✔
6783
      return p_output_symbol();
52✔
UNCOV
6784
   default:
×
UNCOV
6785
      one_of(tUDPLEVEL, tMINUS);
×
6786
   }
6787

6788
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
27✔
6789
   vlog_set_subkind(v, V_UDP_SYMBOL_OUTPUT);
27✔
6790
   vlog_set_ival(v, '-');
27✔
6791

6792
   vlog_set_loc(v, CURRENT_LOC);
27✔
6793
   return v;
27✔
6794
}
6795

6796
static vlog_node_t p_edge_symbol(void)
22✔
6797
{
6798
   // r | R | f | F | p | P | n | N | *
6799

6800
   BEGIN("edge symbol");
22✔
6801

6802
   consume(tUDPEDGE);
22✔
6803

6804
   char left, right;
22✔
6805
   switch (state.last_lval.i64) {
22✔
6806
   case 'r': case 'R': left = '0'; right = '1'; break;
UNCOV
6807
   case 'f': case 'F': left = '1'; right = '0'; break;
×
6808
   case 'p': case 'P': left = '?'; right = '1'; break;
6✔
6809
   case 'n': case 'N': left = '?'; right = '0'; break;
3✔
6810
   case '*':           left = '?'; right = '?'; break;
10✔
6811
   default: should_not_reach_here();
6812
   }
6813

6814
   vlog_node_t lsym = vlog_new(V_UDP_LEVEL);
22✔
6815
   vlog_set_ival(lsym, left);
22✔
6816

6817
   vlog_node_t rsym = vlog_new(V_UDP_LEVEL);
22✔
6818
   vlog_set_ival(rsym, right);
22✔
6819

6820
   vlog_node_t v = vlog_new(V_UDP_EDGE);
22✔
6821
   vlog_set_subkind(v, V_UDP_SYMBOL_INPUT);
22✔
6822
   vlog_set_left(v, lsym);
22✔
6823
   vlog_set_right(v, rsym);
22✔
6824

6825
   vlog_set_loc(v, CURRENT_LOC);
22✔
6826
   return v;
22✔
6827
}
6828

6829
static void p_level_input_list(vlog_node_t entry)
23✔
6830
{
6831
   // level_symbol { level_symbol }
6832

6833
   BEGIN("level input list");
46✔
6834

6835
   do {
66✔
6836
      vlog_add_param(entry, p_level_symbol());
66✔
6837
   } while (not_at_token(tCOLON));
66✔
6838
}
23✔
6839

6840
static vlog_node_t p_edge_indicator(void)
79✔
6841
{
6842
   // ( level_symbol level_symbol ) | edge_symbol
6843

6844
   BEGIN("edge indicator");
158✔
6845

6846
   switch (peek()) {
79✔
6847
   case tUDPEDGE:
22✔
6848
      return p_edge_symbol();
22✔
6849
   case tLPAREN:
57✔
6850
      {
6851
         consume(tLPAREN);
57✔
6852

6853
         vlog_node_t v = vlog_new(V_UDP_EDGE);
57✔
6854
         vlog_set_left(v, p_level_symbol());
57✔
6855
         vlog_set_right(v, p_level_symbol());
57✔
6856

6857
         consume(tRPAREN);
57✔
6858

6859
         vlog_set_loc(v, CURRENT_LOC);
57✔
6860
         return v;
57✔
6861
      }
UNCOV
6862
      break;
×
UNCOV
6863
   default:
×
6864
      should_not_reach_here();
6865
   }
6866
}
6867

6868
static void p_seq_input_list(vlog_node_t entry)
79✔
6869
{
6870
   // level_input_list | edge_input_list
6871

6872
   BEGIN("sequential input list");
158✔
6873

6874
   bool have_edge = false;
79✔
6875
   do {
157✔
6876
      switch (peek()) {
157✔
6877
      case tUDPEDGE:
79✔
6878
      case tLPAREN:
6879
         vlog_add_param(entry, p_edge_indicator());
79✔
6880
         if (have_edge)
79✔
6881
            parse_error(&state.last_loc, "a sequential input list may have at "
1✔
6882
                        "most one edge indicator");
6883
         have_edge = true;
6884
         break;
6885

6886
      case tUDPLEVEL:
78✔
6887
         vlog_add_param(entry, p_level_symbol());
78✔
6888
         break;
78✔
6889

UNCOV
6890
      default:
×
UNCOV
6891
         one_of(tUDPEDGE, tUDPIND, tUDPLEVEL);
×
UNCOV
6892
         break;
×
6893
      }
6894
   } while (not_at_token(tCOLON));
157✔
6895
}
79✔
6896

6897
static vlog_node_t p_combinational_entry(void)
23✔
6898
{
6899
   // level_input_list : output_symbol ;
6900

6901
   BEGIN("combinational entry");
23✔
6902

6903
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
23✔
6904
   p_level_input_list(v);
23✔
6905

6906
   consume(tCOLON);
23✔
6907

6908
   vlog_add_param(v, p_output_symbol());
23✔
6909

6910
   consume(tSEMI);
23✔
6911

6912
   vlog_set_loc(v, CURRENT_LOC);
23✔
6913
   return v;
23✔
6914
}
6915

6916
static vlog_node_t p_combinational_body(void)
7✔
6917
{
6918
   // table combinational_entry { combinational_entry } endtable
6919

6920
   BEGIN("combinational UDP body");
7✔
6921

6922
   consume(tTABLE);
7✔
6923

6924
   scan_as_udp();
7✔
6925

6926
   vlog_node_t v = vlog_new(V_UDP_TABLE);
7✔
6927
   vlog_set_subkind(v, V_UDP_COMB);
7✔
6928
   vlog_set_ident(v, ident_new("combinational"));
7✔
6929

6930
   do {
23✔
6931
      vlog_add_param(v, p_combinational_entry());
23✔
6932
   } while (not_at_token(tENDTABLE));
23✔
6933

6934
   scan_as_verilog();
7✔
6935

6936
   consume(tENDTABLE);
7✔
6937

6938
   vlog_set_loc(v, CURRENT_LOC);
7✔
6939
   return v;
7✔
6940
}
6941

6942
static vlog_node_t p_sequential_entry(void)
79✔
6943
{
6944
   // seq_input_list : current_state : next_state ;
6945

6946
   BEGIN("sequential entry");
79✔
6947

6948
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
79✔
6949
   p_seq_input_list(v);
79✔
6950

6951
   consume(tCOLON);
79✔
6952

6953
   vlog_add_param(v, p_level_symbol());
79✔
6954

6955
   consume(tCOLON);
79✔
6956

6957
   vlog_add_param(v, p_next_state());
79✔
6958

6959
   consume(tSEMI);
79✔
6960

6961
   vlog_set_loc(v, CURRENT_LOC);
79✔
6962
   return v;
79✔
6963
}
6964

6965
static vlog_node_t p_udp_initial_statement(void)
5✔
6966
{
6967
   // initial output_port_identifier = init_val ;
6968

6969
   BEGIN("UDP initial statement");
5✔
6970

6971
   consume(tINITIAL);
5✔
6972

6973
   vlog_node_t ref = vlog_new(V_REF);
5✔
6974
   vlog_set_ident(ref, p_identifier());
5✔
6975
   vlog_set_loc(ref, &state.last_loc);
5✔
6976

6977
   vlog_symtab_lookup(symtab, ref);
5✔
6978

6979
   consume(tEQ);
5✔
6980

6981
   vlog_node_t v = vlog_new(V_BASSIGN);
5✔
6982
   vlog_set_target(v, ref);
5✔
6983
   vlog_set_value(v, p_integral_number());
5✔
6984

6985
   consume(tSEMI);
5✔
6986

6987
   vlog_set_loc(v, CURRENT_LOC);
5✔
6988
   return v;
5✔
6989
}
6990

6991
static vlog_node_t p_sequential_body(void)
12✔
6992
{
6993
   // [ udp_initial_statement ] table sequential_entry
6994
   //     { sequential_entry } endtable
6995

6996
   BEGIN("sequential UDP body");
12✔
6997

6998
   vlog_node_t v = vlog_new(V_UDP_TABLE);
12✔
6999
   vlog_set_subkind(v, V_UDP_SEQ);
12✔
7000
   vlog_set_ident(v, ident_new("sequential"));
12✔
7001

7002
   if (peek() == tINITIAL)
12✔
7003
      vlog_add_stmt(v, p_udp_initial_statement());
5✔
7004

7005
   consume(tTABLE);
12✔
7006

7007
   scan_as_udp();
12✔
7008

7009
   do {
79✔
7010
      vlog_add_param(v, p_sequential_entry());
79✔
7011
   } while (not_at_token(tENDTABLE));
79✔
7012

7013
   scan_as_verilog();
12✔
7014

7015
   consume(tENDTABLE);
12✔
7016

7017
   vlog_set_loc(v, CURRENT_LOC);
12✔
7018
   return v;
12✔
7019
}
7020

7021
static vlog_node_t p_udp_body(bool has_reg)
19✔
7022
{
7023
   // combinational_body | sequential_body
7024

7025
   BEGIN("UDP body");
38✔
7026

7027
   if (has_reg)
19✔
7028
      return p_sequential_body();
12✔
7029
   else
7030
      return p_combinational_body();
7✔
7031
}
7032

7033
static vlog_node_t p_udp_ansi_declaration(bool *has_reg)
1✔
7034
{
7035
   // { attribute_instance } primitive udp_identifier
7036
   //    ( udp_declaration_port_list ) ;
7037

7038
   BEGIN("UDP ANSI declaration");
1✔
7039

7040
   optional_attributes();
1✔
7041

7042
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
1✔
7043

7044
   consume(tPRIMITIVE);
1✔
7045

7046
   ident_t id, ext;
1✔
7047
   p_external_identifier(&id, &ext);
1✔
7048
   vlog_set_ident2(udp, id);
1✔
7049

7050
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
1✔
7051
   vlog_set_ident(udp, qual);
1✔
7052

7053
   vlog_symtab_push(symtab, udp);
1✔
7054

7055
   consume(tLPAREN);
1✔
7056

7057
   p_udp_declaration_port_list(udp, has_reg);
1✔
7058

7059
   consume(tRPAREN);
1✔
7060
   consume(tSEMI);
1✔
7061

7062
   vlog_set_loc(udp, CURRENT_LOC);
1✔
7063
   return udp;
1✔
7064
}
7065

7066
static vlog_node_t p_udp_declaration(void)
19✔
7067
{
7068
   // udp_nonansi_declaration udp_port_declaration { udp_port_declaration }
7069
   //        udp_body endprimitive [ : udp_identifier ]
7070
   //   | udp_ansi_declaration udp_body endprimitive [ : udp_identifier ]
7071
   //   | extern udp_nonansi_declaration
7072
   //   | extern udp_ansi_declaration
7073
   //   | { attribute_instance } primitive udp_identifier ( .* ) ;
7074
   //        { udp_port_declaration } udp_body endprimitive [ : udp_identifier ]
7075

7076
   BEGIN("UDP declaration");
19✔
7077

7078
   bool has_reg = false;
19✔
7079
   vlog_node_t udp;
19✔
7080
   if (peek_nth(4) == tID) {
19✔
7081
      udp = p_udp_nonansi_declaration();
18✔
7082

7083
      vlog_symtab_push(symtab, udp);
18✔
7084

7085
      do {
46✔
7086
         p_udp_port_declaration(udp, &has_reg);
46✔
7087
      } while (not_at_token(tTABLE, tINITIAL));
46✔
7088

7089
      const int nports = vlog_ports(udp);
18✔
7090
      for (int i = 0; i < nports; i++)
77✔
7091
         vlog_symtab_lookup(symtab, vlog_port(udp, i));
59✔
7092
   }
7093
   else
7094
      udp = p_udp_ansi_declaration(&has_reg);
1✔
7095

7096
   vlog_add_stmt(udp, p_udp_body(has_reg));
19✔
7097

7098
   vlog_symtab_pop(symtab);
19✔
7099

7100
   consume(tENDPRIMITIVE);
19✔
7101

7102
   return udp;
19✔
7103
}
7104

7105
static void p_package_item(vlog_node_t parent)
7✔
7106
{
7107
   // package_or_generate_item_declaration | anonymous_program
7108
   //   | package_export_declaration | timeunits_declaration
7109

7110
   BEGIN("package item");
14✔
7111

7112
   p_package_or_generate_item_declaration(parent);
7✔
7113
}
7✔
7114

7115
static vlog_node_t p_package_declaration(void)
2✔
7116
{
7117
   // { attribute_instance } package [ lifetime ] package_identifier ;
7118
   //    [ timeunits_declaration ] { { attribute_instance } package_item }
7119
   // endpackage [ : package_identifier ]
7120

7121
   BEGIN("package declaration");
2✔
7122

7123
   consume(tPACKAGE);
2✔
7124

7125
   if (scan(tSTATIC, tAUTOMATIC))
2✔
UNCOV
7126
      p_lifetime();
×
7127

7128
   vlog_node_t v = vlog_new(V_PACKAGE);
2✔
7129

7130
   ident_t id, ext;
2✔
7131
   p_external_identifier(&id, &ext);
2✔
7132
   vlog_set_ident2(v, id);
2✔
7133

7134
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
2✔
7135
   vlog_set_ident(v, qual);
2✔
7136

7137
   consume(tSEMI);
2✔
7138

7139
   while (not_at_token(tENDPACKAGE)) {
6✔
7140
      optional_attributes();
4✔
7141
      p_package_item(v);
4✔
7142
   }
7143

7144
   consume(tENDPACKAGE);
2✔
7145

7146
   if (optional(tCOLON)) {
2✔
7147
      ident_t name = p_identifier();
2✔
7148
      if (id != name)
2✔
7149
         error_at(&state.last_loc, "'%s' does not match package name '%s'",
1✔
7150
                  istr(name), istr(id));
7151
   }
7152

7153
   vlog_set_loc(v, CURRENT_LOC);
2✔
7154
   return v;
2✔
7155
}
7156

7157
static vlog_node_t p_program_nonansi_header(void)
5✔
7158
{
7159
   // { attribute_instance } program [ lifetime ] program_identifier
7160
   //    { package_import_declaration } [ parameter_port_list ] list_of_ports ;
7161

7162
   BEGIN("program non-ANSI header");
5✔
7163

7164
   optional_attributes();
5✔
7165

7166
   vlog_node_t v = vlog_new(V_PROGRAM);
5✔
7167

7168
   consume(tPROGRAM);
5✔
7169

7170
   ident_t id, ext;
5✔
7171
   p_external_identifier(&id, &ext);
5✔
7172
   vlog_set_ident2(v, id);
5✔
7173

7174
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
5✔
7175
   vlog_set_ident(v, qual);
5✔
7176

7177
   consume(tSEMI);
5✔
7178

7179
   vlog_set_loc(v, CURRENT_LOC);
5✔
7180
   return v;
5✔
7181
}
7182

7183
static void p_non_port_program_item(vlog_node_t parent)
20✔
7184
{
7185
   // { attribute_instance } continuous_assign
7186
   //   | { attribute_instance } module_or_generate_item_declaration
7187
   //   | { attribute_instance } initial_construct
7188
   //   | { attribute_instance } final_construct
7189
   //   | { attribute_instance } concurrent_assertion_item
7190
   //   | timeunits_declaration
7191
   //   | program_generate_item
7192

7193
   BEGIN("non-port program item");
40✔
7194

7195
   optional_attributes();
20✔
7196

7197
   switch (peek()) {
20✔
7198
   case tINITIAL:
5✔
7199
      vlog_add_stmt(parent, p_initial_construct());
5✔
7200
      break;
5✔
7201
   default:
15✔
7202
      p_module_or_generate_item_declaration(parent);
15✔
7203
      break;
15✔
7204
   }
7205
}
20✔
7206

7207
static vlog_node_t p_program_declaration(void)
5✔
7208
{
7209
   // program_nonansi_header [ timeunits_declaration ] { program_item }
7210
   //       endprogram [ : program_identifier ]
7211
   //   | program_ansi_header [ timeunits_declaration ]
7212
   //       { non_port_program_item }
7213
   //   | { attribute_instance } program program_identifier ( .* ) ;
7214
   //       [ timeunits_declaration ] { program_item } endprogram
7215
   //       [ : program_identifier ]
7216
   //   | extern program_nonansi_header
7217
   //   | extern program_ansi_header
7218

7219
   BEGIN("program declaration");
5✔
7220

7221
   vlog_node_t v = p_program_nonansi_header();
5✔
7222

7223
   while (not_at_token(tENDPROGRAM))
25✔
7224
      p_non_port_program_item(v);
20✔
7225

7226
   consume(tENDPROGRAM);
5✔
7227

7228
   if (optional(tCOLON)) {
5✔
7229
      ident_t name = p_identifier();
1✔
7230
      if (name != vlog_ident2(v))
1✔
7231
         parse_error(&state.last_loc, "'%s' does not match program name '%s'",
1✔
7232
                     istr(name), istr(vlog_ident2(v)));
7233
   }
7234

7235
   vlog_set_loc(v, CURRENT_LOC);
5✔
7236
   return v;
5✔
7237
}
7238

7239
static vlog_node_t p_description(void)
420✔
7240
{
7241
   // module_declaration | udp_declaration | interface_declaration
7242
   //   | program_declaration | package_declaration
7243
   //   | { attribute_instance } package_item
7244
   //   | { attribute_instance } bind_directive
7245
   //   | config_declaration
7246

7247
   BEGIN("description");
840✔
7248

7249
   skip_over_attributes();
420✔
7250

7251
   switch (peek()) {
420✔
7252
   case tMODULE:
391✔
7253
      return p_module_declaration();
391✔
7254
   case tPRIMITIVE:
19✔
7255
      return p_udp_declaration();
19✔
7256
   case tPACKAGE:
2✔
7257
      return p_package_declaration();
2✔
7258
   case tPROGRAM:
5✔
7259
      return p_program_declaration();
5✔
7260
   case tCLASS:
3✔
7261
   case tTYPEDEF:
7262
      {
7263
         vlog_node_t v = vlog_new(V_NAMESPACE);
3✔
7264
         p_package_item(v);
3✔
7265
         vlog_set_loc(v, CURRENT_LOC);
3✔
7266
         return v;
3✔
7267
      }
UNCOV
7268
   default:
×
UNCOV
7269
      expect(tPRIMITIVE, tMODULE, tPACKAGE, tPROGRAM, tCLASS, tTYPEDEF);
×
UNCOV
7270
      return NULL;
×
7271
   }
7272
}
7273

7274
static void p_timescale_compiler_directive(void)
13✔
7275
{
7276
   // `timescale time_unit / time_precision
7277

7278
   BEGIN("timescale compiler directive");
26✔
7279

7280
   consume(tTIMESCALE);
13✔
7281

7282
   uint64_t unit_value = 1;
13✔
7283
   if (consume(tUNSNUM))
13✔
7284
      unit_value = atoll(state.last_lval.str);
12✔
7285

7286
   const char *unit_name = "fs";
13✔
7287
   if (consume(tID))
13✔
7288
      unit_name = istr(state.last_lval.ident);
13✔
7289

7290
   consume(tOVER);
13✔
7291

7292
   uint64_t prec_value = 1;
13✔
7293
   if (consume(tUNSNUM))
13✔
7294
      prec_value = atoll(state.last_lval.str);
12✔
7295

7296
   const char *prec_name = "fs";
13✔
7297
   if (consume(tID))
13✔
7298
      prec_name = istr(state.last_lval.ident);
12✔
7299

7300
   set_timescale(unit_value, unit_name, prec_value, prec_name, CURRENT_LOC);
13✔
7301
}
13✔
7302

7303
static void p_defaultnettype_compiler_directive(void)
12✔
7304
{
7305
   // `default_nettype wire | tri | tri0 | tri1 | wand | triand | wor
7306
   //    | trior | trireg | uwire | none
7307

7308
   BEGIN("default_nettype directive");
24✔
7309

7310
   consume(tDEFNETTYPE);
12✔
7311

7312
   switch (one_of(tWIRE, tTRI, tTRI0, tTRI1, tWAND, tTRIAND, tWOR, tTRIOR,
12✔
7313
                  tTRIREG, tUWIRE, tNONE)) {
7314
   case tWIRE: implicit_kind = V_NET_WIRE; break;
1✔
7315
   case tNONE: implicit_kind = V_NET_NONE; break;
1✔
7316
   }
7317
}
12✔
7318

7319
static void p_unconnected_drive_directive(void)
2✔
7320
{
7321
   // `unconnected_drive pull0 | pull1
7322

7323
   BEGIN("unconnected_drive directive");
4✔
7324

7325
   consume(tUNCTDRIVE);
2✔
7326

7327
   // TODO set default drive for unconnected nets
7328
   one_of(tPULL0, tPULL1);
2✔
7329
}
2✔
7330

7331
static void p_nounconnected_drive_directive(void)
1✔
7332
{
7333
   // `nounconnected_drive
7334

7335
   BEGIN("nounconnected_drive directive");
2✔
7336

7337
   consume(tNOUNCTDRIVE);
1✔
7338

7339
   // TODO reset default drive for unconnected nets
7340
}
1✔
7341

7342
static void p_keywords_directive(void)
4✔
7343
{
7344
   // `begin_keywords "version_specifier"
7345

7346
   BEGIN("keywords directive");
8✔
7347

7348
   consume(tBEGINKEYWORDS);
4✔
7349

7350
   if (consume(tSTRING)) {
4✔
7351
      vlog_version_t vers;
3✔
7352
      if (parse_verilog_version(tb_get(state.last_lval.text), &vers))
3✔
7353
         push_keywords(vers);
2✔
7354
      else
7355
         error_at(&state.last_loc, "\"%s\" is not a recognised Verilog or "
1✔
7356
                  "System Verilog version", tb_get(state.last_lval.text));
7357

7358
      tb_free(state.last_lval.text);
3✔
7359
   }
7360
}
4✔
7361

7362
static void p_endkeywords_directive(void)
3✔
7363
{
7364
   // `end_keywords
7365

7366
   BEGIN("endkeywords directive");
6✔
7367

7368
   consume(tENDKEYWORDS);
3✔
7369

7370
   if (!pop_keywords())
3✔
7371
      error_at(&state.last_loc, "`end_keywords directive without matching "
1✔
7372
               "`begin_keywords");
7373
}
3✔
7374

7375
static void p_resetall_directive(void)
1✔
7376
{
7377
   // `resetall
7378

7379
   BEGIN("resetall directive");
1✔
7380

7381
   consume(tRESETALL);
1✔
7382

7383
   implicit_kind = V_NET_WIRE;
1✔
7384
}
1✔
7385

7386
static void p_directive_list(void)
756✔
7387
{
7388
   BEGIN("directive list");
756✔
7389

7390
   for (;;) {
792✔
7391
      switch (peek()) {
792✔
7392
      case tDEFNETTYPE:
12✔
7393
         p_defaultnettype_compiler_directive();
12✔
7394
         break;
12✔
7395
      case tTIMESCALE:
13✔
7396
         p_timescale_compiler_directive();
13✔
7397
         break;
13✔
7398
      case tUNCTDRIVE:
2✔
7399
         p_unconnected_drive_directive();
2✔
7400
         break;
2✔
7401
      case tNOUNCTDRIVE:
1✔
7402
         p_nounconnected_drive_directive();
1✔
7403
         break;
1✔
7404
      case tBEGINKEYWORDS:
4✔
7405
         p_keywords_directive();
4✔
7406
         break;
4✔
7407
      case tENDKEYWORDS:
3✔
7408
         p_endkeywords_directive();
3✔
7409
         break;
3✔
7410
      case tRESETALL:
1✔
7411
         p_resetall_directive();
1✔
7412
         break;
1✔
7413
      default:
7414
         return;
756✔
7415
      }
7416
   }
7417
}
7418

7419
static vlog_node_t end_of_file(void)
339✔
7420
{
7421
   vlog_symtab_pop(symtab);
339✔
7422
   vlog_symtab_free(symtab);
339✔
7423
   symtab = NULL;
339✔
7424
   return NULL;
339✔
7425
}
7426

7427
static vlog_node_t p_source_text(void)
418✔
7428
{
7429
   // [ timeunits_declaration ] { description }
7430

7431
   BEGIN("source text");
836✔
7432

7433
   for (;;) {
421✔
7434
      if (peek() == tEOF) {
421✔
7435
         discard_global_arena();
1✔
7436
         return end_of_file();
1✔
7437
      }
7438

7439
      vlog_node_t v = p_description();
420✔
7440
      if (v == NULL || is_top_level(v))
420✔
7441
         return v;
417✔
7442
   }
7443
}
7444

7445
vlog_node_t vlog_parse(void)
756✔
7446
{
7447
   state.n_correct = RECOVER_THRESH;
756✔
7448
   param_kind = V_PARAM_DECL;
756✔
7449

7450
   scan_as_verilog();
756✔
7451

7452
   if (symtab == NULL) {
756✔
7453
      symtab = vlog_symtab_new();
340✔
7454
      vlog_symtab_push(symtab, NULL);   // Compilation unit scope
340✔
7455
      vlog_symtab_poison(symtab, error_marker());
340✔
7456
   }
7457

7458
   p_directive_list();
756✔
7459

7460
   if (peek() == tEOF)
756✔
7461
      return end_of_file();
338✔
7462

7463
   make_new_arena();
418✔
7464

7465
   return p_source_text();
418✔
7466
}
7467

7468
void reset_verilog_parser(void)
647✔
7469
{
7470
   state.tokenq_head = state.tokenq_tail = 0;
647✔
7471
   implicit_kind = V_NET_WIRE;
647✔
7472
   last_attr = NULL;
647✔
7473

7474
   if (symtab != NULL) {
647✔
UNCOV
7475
      vlog_symtab_free(symtab);
×
UNCOV
7476
      symtab = NULL;
×
7477
   }
7478
}
647✔
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