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

nickg / nvc / 16103786966

06 Jul 2025 10:26PM UTC coverage: 92.332% (-0.01%) from 92.345%
16103786966

Pull #1232

github

web-flow
Merge 969b15cdc into 6fafc646d
Pull Request #1232: Improve net declaration parsing

119 of 140 new or added lines in 2 files covered. (85.0%)

2 existing lines in 1 file now uncovered.

71335 of 77259 relevant lines covered (92.33%)

562656.03 hits per line

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

95.97
/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)
47,636✔
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;
47,636✔
128

129
   if (r->old_start_loc.first_line != LINE_INVALID)
47,636✔
130
      state.start_loc = r->old_start_loc;
15,519✔
131
}
47,636✔
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)
90,819✔
141
{
142
   while (((state.tokenq_head - state.tokenq_tail) & (TOKENQ_SIZE - 1)) < n) {
112,094✔
143
      const token_t token = processed_yylex();
21,275✔
144

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

148
      extern yylval_t yylval;
21,275✔
149

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

154
      state.tokenq_head = next;
21,275✔
155
   }
156

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

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

165
   if (state.start_loc.first_line == LINE_INVALID)
21,083✔
166
      state.start_loc = state.tokenq[state.tokenq_tail].loc;
11,362✔
167

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

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

173
   state.nopt_hist = 0;
21,083✔
174
}
21,083✔
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)
11✔
192
{
193
   if (state.n_correct >= RECOVER_THRESH) {
11✔
194
      diag_t *d = diag_new(DIAG_ERROR, &(state.tokenq[state.tokenq_tail].loc));
6✔
195
      diag_printf(d, "unexpected $yellow$%s$$ while parsing %s, expecting ",
6✔
196
                  token_str(peek()), state.hint_str);
197

198
      bool first = true;
6✔
199
      for (int i = 0; i < state.nopt_hist; i++) {
10✔
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);
6✔
206
      while (tok != -1) {
74✔
207
         const int tmp = tok;
68✔
208
         tok = va_arg(ap, int);
68✔
209

210
         if (first && (tok != -1))
68✔
211
            diag_printf(d, "one of ");
3✔
212
         else if (!first)
65✔
213
            diag_printf(d, (tok == -1) ? " or " : ", ");
124✔
214

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

217
         first = false;
68✔
218
      }
219

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

225
   state.n_correct = 0;
11✔
226

227
   drop_token();
11✔
228

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

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

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

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

261
static bool optional(token_t tok)
11,709✔
262
{
263
   if (peek() == tok) {
11,709✔
264
      consume(tok);
2,222✔
265
      return true;
2,222✔
266
   }
267
   else {
268
      if (state.nopt_hist < ARRAY_LEN(state.opt_hist))
9,487✔
269
         state.opt_hist[state.nopt_hist++] = tok;
9,487✔
270
      return false;
9,487✔
271
   }
272
}
273

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

279
   token_t p = peek();
6,049✔
280
   bool found = false;
6,049✔
281

282
   while (!found) {
6,049✔
283
      const int tok = va_arg(ap, token_t);
20,220✔
284
      if (tok == -1)
20,220✔
285
         break;
286
      else if (p == tok)
15,240✔
287
         found = true;
288
   }
289

290
   va_end(ap);
6,049✔
291
   return found;
6,049✔
292
}
293

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

299
   token_t p = peek();
1,455✔
300
   bool found = false;
1,455✔
301

302
   while (!found) {
1,455✔
303
      const int tok = va_arg(ap, token_t);
5,596✔
304
      if (tok == -1)
5,596✔
305
         break;
306
      else if (p == tok)
5,589✔
307
         found = true;
308
   }
309

310
   va_end(ap);
1,455✔
311

312
   if (found) {
1,455✔
313
      consume(p);
1,448✔
314
      return p;
1,448✔
315
   }
316
   else {
317
      va_start(ap, dummy);
7✔
318
      _vexpect(ap);
7✔
319
      va_end(ap);
7✔
320

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

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

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

337
static void set_timescale(const char *unit_value, const char *unit_name,
11✔
338
                          const char *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 {
11✔
344
      const char *value;
345
      const char *name;
346
      int64_t     parsed;
347
   } args[] = {
11✔
348
      { unit_value, unit_name },
349
      { prec_value, prec_name },
350
   };
351

352
   for (int i = 0; i < ARRAY_LEN(args); i++) {
33✔
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;
104✔
366
      for (int j = 0; j < ARRAY_LEN(valid_units); j++) {
104✔
367
         if (strcmp(valid_units[j].name, args[i].name) == 0) {
103✔
368
            args[i].parsed = valid_units[j].value;
21✔
369
            name_valid = true;
21✔
370
            break;
21✔
371
         }
372
      }
373

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

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

385
      args[i].parsed *= scale;
22✔
386
   }
387

388
   // TODO: do something with parsed scale/precision
389
}
11✔
390

391
static void skip_over_attributes(void)
709✔
392
{
393
   while (peek() == tATTRBEGIN)
716✔
394
      last_attr = p_attribute_instance();
7✔
395
}
709✔
396

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

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

413
   last_attr = NULL;
3,866✔
414
}
3,866✔
415

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

421
static vlog_node_t dummy_expression(void)
×
422
{
423
   vlog_node_t v = vlog_new(V_NUMBER);
×
424
   vlog_set_number(v, number_new("1'b0", NULL));
×
425
   return v;
×
426
}
427

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

435
static ident_t p_identifier(void)
3,184✔
436
{
437
   if (consume(tID)) {
3,184✔
438
      ident_t id = ident_new(state.last_lval.str);
3,183✔
439
      free(state.last_lval.str);
3,183✔
440
      return id;
3,183✔
441
   }
442
   else
443
      return error_marker();
1✔
444
}
445

446
static void p_external_identifier(ident_t *id, ident_t *ext)
469✔
447
{
448
   if (consume(tID)) {
469✔
449
      *id = ident_new(state.last_lval.str);
469✔
450
      for (char *p = state.last_lval.str; *p; p++)
2,353✔
451
         *p = toupper_iso88591(*p);
1,884✔
452
      *ext = ident_new(state.last_lval.str);
469✔
453
      free(state.last_lval.str);
469✔
454
   }
455
   else
456
      *id = *ext = error_marker();
×
457
}
469✔
458

459
static ident_t p_system_tf_identifier(void)
900✔
460
{
461
   if (consume(tSYSTASK)) {
900✔
462
      ident_t id = ident_new(state.last_lval.str);
900✔
463
      free(state.last_lval.str);
900✔
464
      return id;
900✔
465
   }
466
   else
467
      return error_marker();
×
468
}
469

470
static void p_attr_spec(void)
20✔
471
{
472
   // attr_name [ = constant_expression ]
473

474
   BEGIN("attribute specification");
40✔
475

476
   (void)p_identifier();
20✔
477

478
   if (optional(tEQ))
20✔
479
      (void)p_constant_expression();
1✔
480
}
20✔
481

482
static vlog_node_t p_attribute_instance(void)
20✔
483
{
484
   // (* attr_spec { , attr_spec } *)
485

486
   BEGIN("attribute instance");
20✔
487

488
   consume(tATTRBEGIN);
20✔
489

490
   vlog_node_t v = vlog_new(V_ATTR_INST);
20✔
491

492
   do {
20✔
493
      p_attr_spec();
20✔
494
   } while (optional(tCOMMA));
20✔
495

496
   consume(tATTREND);
20✔
497

498
   vlog_set_loc(v, CURRENT_LOC);
20✔
499
   return v;
20✔
500
}
501

502
static vlog_node_t p_unsigned_number(void)
1,908✔
503
{
504
   // decimal_digit { _ | decimal_digit }
505

506
   BEGIN("unsigned number");
1,908✔
507

508
   consume(tUNSIGNED);
1,908✔
509

510
   vlog_node_t v = vlog_new(V_NUMBER);
1,908✔
511
   vlog_set_loc(v, CURRENT_LOC);
1,908✔
512
   vlog_set_number(v, number_new(state.last_lval.str, CURRENT_LOC));
1,908✔
513
   free(state.last_lval.str);
1,908✔
514
   return v;
1,908✔
515
}
516

517
static vlog_node_t p_integral_number(void)
1,752✔
518
{
519
   // decimal_number | octal_number | binary_number | hex_number
520

521
   BEGIN("integral number");
3,504✔
522

523
   if (peek() == tUNSIGNED)
1,752✔
524
      return p_unsigned_number();
1,569✔
525
   else {
526
      consume(tNUMBER);
183✔
527

528
      vlog_node_t v = vlog_new(V_NUMBER);
183✔
529
      vlog_set_loc(v, CURRENT_LOC);
183✔
530
      vlog_set_number(v, number_new(state.last_lval.str, CURRENT_LOC));
183✔
531
      free(state.last_lval.str);
183✔
532
      return v;
183✔
533
   }
534
}
535

536
static vlog_node_t p_real_number(void)
23✔
537
{
538
   // fixed_point_number
539
   //   | unsigned_number [ . unsigned_number ] exp [ sign ] unsigned_number
540

541
   BEGIN("real number");
23✔
542

543
   consume(tREAL);
23✔
544

545
   vlog_node_t v = vlog_new(V_REAL);
23✔
546
   vlog_set_dval(v, state.last_lval.real);
23✔
547
   vlog_set_loc(v, CURRENT_LOC);
23✔
548
   return v;
23✔
549
}
550

551
static vlog_node_t p_number(void)
1,770✔
552
{
553
   // integral_number | real_number
554

555
   BEGIN("number");
3,540✔
556

557
   if (peek() == tREAL)
1,770✔
558
      return p_real_number();
23✔
559
   else
560
      return p_integral_number();
1,747✔
561
}
562

563
static vlog_node_t p_string_literal(void)
601✔
564
{
565
   // " { Any_ASCII_Characters } "
566

567
   BEGIN("string literal");
601✔
568

569
   consume(tSTRING);
601✔
570

571
   vlog_node_t v = vlog_new(V_STRING);
601✔
572
   vlog_set_loc(v, CURRENT_LOC);
601✔
573
   vlog_set_number(v, number_new(state.last_lval.str, CURRENT_LOC));
601✔
574

575
   return v;
601✔
576
}
577

578
static vlog_node_t p_primary_literal(void)
2,371✔
579
{
580
   // number | time_literal | unbased_unsized_literal | string_literal
581

582
   BEGIN("primary literal");
4,742✔
583

584
   switch (peek()) {
2,371✔
585
   case tNUMBER:
1,770✔
586
   case tUNSIGNED:
587
   case tREAL:
588
      return p_number();
1,770✔
589
   case tSTRING:
601✔
590
      return p_string_literal();
601✔
591
   default:
×
592
      one_of(tNUMBER, tUNSIGNED, tREAL, tSTRING);
×
593
      return dummy_expression();
×
594
   }
595
}
596

597
static vlog_node_t p_constant_select(ident_t id)
162✔
598
{
599
   // [ { . member_identifier constant_bit_select } . member_identifier ]
600
   //    constant_bit_select [ [ constant_part_select_range ] ]
601

602
   EXTEND("constant select");
324✔
603

604
   // Checked for constant-ness later
605
   return p_select(id);
162✔
606
}
607

608
static vlog_node_t p_constant_expression(void)
447✔
609
{
610
   // constant_primary | unary_operator { attribute_instance } constant_primary
611
   //   | constant_expression binary_operator { attribute_instance }
612
   //       constant_expression
613
   //   | constant_expression ? { attribute_instance }
614
   //       constant_expression : constant_expression
615

616
   BEGIN("constant expression");
894✔
617

618
   // Checked for constant-ness later
619
   return p_expression();
447✔
620
}
621

622
static void p_constant_range(vlog_node_t *left, vlog_node_t *right)
190✔
623
{
624
   // constant_expression : constant_expression
625

626
   BEGIN("constant range");
190✔
627

628
   *left = p_constant_expression();
190✔
629

630
   consume(tCOLON);
190✔
631

632
   *right = p_constant_expression();
190✔
633
}
190✔
634

635
static vlog_node_t p_constant_range_expression(void)
2✔
636
{
637
   // constant_expression | constant_part_select_range
638

639
   BEGIN("constant range expression");
4✔
640

641
   return p_constant_expression();
2✔
642
}
643

644
static vlog_node_t p_constant_mintypmax_expression(void)
2✔
645
{
646
   // constant_expression
647
   //   | constant_expression : constant_expression : constant_expression
648

649
   return p_constant_expression();
2✔
650
}
651

652
static vlog_node_t p_packed_dimension(void)
174✔
653
{
654
   // [ constant_range ] | unsized_dimension
655

656
   BEGIN("packed dimension");
174✔
657

658
   consume(tLSQUARE);
174✔
659

660
   vlog_node_t left, right;
174✔
661
   p_constant_range(&left, &right);
174✔
662

663
   consume(tRSQUARE);
174✔
664

665
   vlog_node_t v = vlog_new(V_DIMENSION);
174✔
666
   vlog_set_subkind(v, V_DIM_PACKED);
174✔
667
   vlog_set_left(v, left);
174✔
668
   vlog_set_right(v, right);
174✔
669
   vlog_set_loc(v, CURRENT_LOC);
174✔
670

671
   return v;
174✔
672
}
673

674
static vlog_node_t p_unpacked_dimension(void)
16✔
675
{
676
   // [ constant_range ] | [ constant_expression ]
677

678
   BEGIN("unpacked dimension");
16✔
679

680
   consume(tLSQUARE);
16✔
681

682
   vlog_node_t left, right;
16✔
683
   p_constant_range(&left, &right);
16✔
684

685
   consume(tRSQUARE);
16✔
686

687
   vlog_node_t v = vlog_new(V_DIMENSION);
16✔
688
   vlog_set_subkind(v, V_DIM_UNPACKED);
16✔
689
   vlog_set_left(v, left);
16✔
690
   vlog_set_right(v, right);
16✔
691
   vlog_set_loc(v, CURRENT_LOC);
16✔
692

693
   return v;
16✔
694
}
695

696
static vlog_node_t p_data_type_or_void(void)
10✔
697
{
698
   // data_type | void
699

700
   BEGIN("data type or void");
20✔
701

702
   if (optional(tVOID))
10✔
703
      return NULL;
704
   else
705
      return p_data_type();
10✔
706
}
707

708
static void p_struct_union_member(vlog_node_t v)
9✔
709
{
710
   // { attribute_instance } [ random_qualifier ] data_type_or_void
711
   //    list_of_variable_decl_assignments ;
712

713
   BEGIN("struct or union member");
18✔
714

715
   optional_attributes();
9✔
716

717
   vlog_node_t dt = p_data_type_or_void();
9✔
718
   p_list_of_variable_decl_assignments(v, dt);
9✔
719

720
   consume(tSEMI);
9✔
721
}
9✔
722

723
static void p_enum_name_declaration(vlog_node_t parent)
4✔
724
{
725
   // enum_identifier [ [ integral_number [ : integral_number ] ] ]
726
   //   [ = constant_expression ]
727

728
   BEGIN("enum name declaration");
8✔
729

730
   vlog_node_t v = vlog_new(V_ENUM_NAME);
4✔
731
   vlog_set_ident(v, p_identifier());
4✔
732
   vlog_set_type(v, parent);
4✔
733

734
   vlog_add_decl(parent, v);
4✔
735

736
   vlog_set_loc(v, CURRENT_LOC);
4✔
737
   vlog_symtab_put(symtab, v);
4✔
738
}
4✔
739

740
static vlog_node_t p_integer_atom_type(void)
23✔
741
{
742
   // byte | shortint | int | longint | integer | time
743

744
   BEGIN("integer atom type");
23✔
745

746
   data_type_t dt = DT_BYTE;
23✔
747
   switch (one_of(tBYTE, tSHORTINT, tSVINT, tLONGINT, tINTEGER, tTIME)) {
23✔
748
   case tBYTE:     dt = DT_BYTE; break;
749
   case tSHORTINT: dt = DT_SHORTINT; break;
750
   case tSVINT:    dt = DT_INT; break;
751
   case tLONGINT:  dt = DT_LONGINT; break;
752
   case tINTEGER:  dt = DT_INTEGER; break;
753
   case tTIME:     dt = DT_TIME; break;
754
   }
755

756
   vlog_node_t v = vlog_new(V_DATA_TYPE);
23✔
757
   vlog_set_subkind(v, dt);
23✔
758
   vlog_set_loc(v, &state.last_loc);
23✔
759
   return v;
23✔
760
}
761

762
static vlog_node_t p_integer_vector_type(void)
262✔
763
{
764
   //  bit | logic | reg
765

766
   BEGIN("integer vector type");
262✔
767

768
   data_type_t dt = DT_LOGIC;
262✔
769
   switch (one_of(tBIT, tLOGIC, tREG)) {
262✔
770
   case tBIT:    dt = DT_BIT; break;
5✔
771
   case tLOGIC:
772
   case tREG:    dt = DT_LOGIC; break;
773
   }
774

775
   vlog_node_t v = vlog_new(V_DATA_TYPE);
262✔
776
   vlog_set_subkind(v, dt);
262✔
777
   vlog_set_loc(v, &state.last_loc);
262✔
778
   return v;
262✔
779
}
780

781
static vlog_node_t p_non_integer_type(void)
8✔
782
{
783
   // shortreal | real | realtime
784

785
   BEGIN("non-integer type");
8✔
786

787
   data_type_t dt = DT_REAL;
8✔
788
   switch (one_of(tSVREAL, tSHORTREAL, tREALTIME)) {
8✔
789
   case tSVREAL:    dt = DT_REAL; break;
790
   case tSHORTREAL: dt = DT_SHORTREAL; break;
1✔
791
   case tREALTIME:  dt = DT_REALTIME; break;
1✔
792
   }
793

794
   vlog_node_t v = vlog_new(V_DATA_TYPE);
8✔
795
   vlog_set_subkind(v, dt);
8✔
796
   vlog_set_loc(v, &state.last_loc);
8✔
797
   return v;
8✔
798
}
799

800
static vlog_node_t p_struct_union(void)
5✔
801
{
802
   // struct | union [ tagged ]
803

804
   BEGIN("struct or union");
10✔
805

806
   switch (one_of(tSTRUCT, tUNION)) {
5✔
807
   case tUNION:
2✔
808
      {
809
         vlog_node_t v = vlog_new(V_UNION_DECL);
2✔
810
         optional(tTAGGED);
2✔
811
         return v;
2✔
812
      }
813
   case tSTRUCT:
3✔
814
   default:
815
      return vlog_new(V_STRUCT_DECL);
3✔
816
   }
817
}
818

819
static vlog_node_t p_data_type(void)
303✔
820
{
821
   // integer_vector_type [ signing ] { packed_dimension }
822
   //   | integer_atom_type [ signing ] | non_integer_type
823
   //   | struct_union [ packed [ signing ] ]
824
   //       { struct_union_member { struct_union_member } } { packed_dimension }
825
   //   | enum [ enum_base_type ] { enum_name_declaration
826
   //       { , enum_name_declaration } } { packed_dimension }
827
   //   | string | chandle
828
   //   | virtual [ interface ] interface_identifier
829
   //       [ parameter_value_assignment ] [ . modport_identifier ]
830
   //   | [ class_scope | package_scope ] type_identifier { packed_dimension }
831
   //   | class_type | event | ps_covergroup_identifier | type_reference
832

833
   BEGIN("data type");
606✔
834

835
   switch (peek()) {
303✔
836
   case tBIT:
262✔
837
   case tLOGIC:
838
   case tREG:
839
      {
840
         vlog_node_t v = p_integer_vector_type();
262✔
841

842
         while (peek() == tLSQUARE)
370✔
843
            vlog_add_range(v, p_packed_dimension());
108✔
844

845
         return v;
846
      }
847

848
   case tBYTE:
23✔
849
   case tSHORTINT:
850
   case tSVINT:
851
   case tLONGINT:
852
   case tINTEGER:
853
   case tTIME:
854
      return p_integer_atom_type();
23✔
855

856
   case tSVREAL:
8✔
857
   case tREALTIME:
858
   case tSHORTREAL:
859
      return p_non_integer_type();
8✔
860

861
   case tSTRUCT:
5✔
862
   case tUNION:
863
      {
864
         vlog_node_t v = p_struct_union();
5✔
865

866
         (void)optional(tPACKED);
5✔
867

868
         consume(tLBRACE);
5✔
869

870
         vlog_symtab_push(symtab, v);
5✔
871

872
         do {
9✔
873
            p_struct_union_member(v);
9✔
874
         } while (not_at_token(tRBRACE));
9✔
875

876
         vlog_symtab_pop(symtab);
5✔
877

878
         consume(tRBRACE);
5✔
879

880
         if (peek() == tLSQUARE)
5✔
881
            vlog_add_range(v, p_packed_dimension());
×
882

883
         vlog_set_loc(v, CURRENT_LOC);
5✔
884
         return v;
5✔
885
      }
886

887
   case tENUM:
2✔
888
      {
889
         consume(tENUM);
2✔
890

891
         vlog_node_t v = vlog_new(V_ENUM_DECL);
2✔
892

893
         consume(tLBRACE);
2✔
894

895
         do {
4✔
896
            p_enum_name_declaration(v);
4✔
897
         } while (optional(tCOMMA));
4✔
898

899
         consume(tRBRACE);
2✔
900

901
         while (peek() == tLSQUARE)
3✔
902
            vlog_add_range(v, p_packed_dimension());
1✔
903

904
         vlog_set_loc(v, CURRENT_LOC);
2✔
905
         return v;
2✔
906
      }
907

908
   case tEVENT:
1✔
909
      {
910
         consume(tEVENT);
1✔
911

912
         vlog_node_t v = vlog_new(V_DATA_TYPE);
1✔
913
         vlog_set_subkind(v, DT_EVENT);
1✔
914
         vlog_set_loc(v, &state.last_loc);
1✔
915

916
         return v;
1✔
917
      }
918

919
   case tID:
2✔
920
      {
921
         ident_t id = p_identifier();
2✔
922
         vlog_node_t dt = vlog_symtab_query(symtab, id);
2✔
923
         if (dt == NULL)
2✔
924
            should_not_reach_here();   // Guarded by peek_reference() call
925
         else if (!is_data_type(dt)) {
2✔
926
            diag_t *d = diag_new(DIAG_ERROR, &state.last_loc);
1✔
927
            diag_printf(d, "'%s' is not a data type", istr(id));
1✔
928
            diag_hint(d, vlog_loc(dt), "'%s' declared here", istr(id));
1✔
929
            diag_emit(d);
1✔
930

931
            return logic_type();
1✔
932
         }
933
         else
934
            return dt;
935
      }
936

937
   default:
×
938
      one_of(tBIT, tLOGIC, tREG, tBYTE, tSHORTINT, tSVINT, tLONGINT, tINTEGER,
×
939
             tTIME, tSVREAL, tREALTIME, tSHORTREAL, tSTRUCT, tUNION, tENUM,
940
             tEVENT, tID);
941
      return logic_type();
×
942
   }
943
}
944

945
static vlog_node_t p_implicit_data_type(void)
286✔
946
{
947
   // [ signing ] { packed_dimension }
948

949
   BEGIN("implicit data type");
286✔
950

951
   vlog_node_t v = vlog_new(V_DATA_TYPE);
286✔
952
   vlog_set_subkind(v, DT_LOGIC);
286✔
953

954
   while (peek() == tLSQUARE)
350✔
955
      vlog_add_range(v, p_packed_dimension());
64✔
956

957
   vlog_set_loc(v, CURRENT_LOC);
286✔
958
   return v;
286✔
959
}
960

961
static vlog_node_t p_data_type_or_implicit(void)
565✔
962
{
963
   // data_type | implicit_data_type
964

965
   BEGIN("data type or implicit");
1,130✔
966

967
   switch (peek()) {
565✔
968
   case tID:
217✔
969
      if (peek_nth(2) == tID)
217✔
970
         return p_data_type();
2✔
971
      else
972
         return p_implicit_data_type();
215✔
973
      break;
282✔
974
   case tREG:
282✔
975
   case tSTRUCT:
976
   case tUNION:
977
   case tENUM:
978
   case tSVINT:
979
   case tINTEGER:
980
   case tSVREAL:
981
   case tSHORTREAL:
982
   case tREALTIME:
983
   case tTIME:
984
   case tLOGIC:
985
   case tBIT:
986
   case tEVENT:
987
      return p_data_type();
282✔
988
   default:
66✔
989
      return p_implicit_data_type();
66✔
990
   }
991
}
992

993
static void p_net_port_type(vlog_net_kind_t *kind, vlog_node_t *dt)
124✔
994
{
995
   // [ net_type ] data_type_or_implicit | net_type_identifier
996
   //   | interconnect implicit_data_type
997

998
   BEGIN("net port type");
124✔
999

1000
   if (scan(tSUPPLY0, tSUPPLY1, tTRI, tTRIAND, tTRIOR, tTRIREG,
124✔
1001
            tTRI0, tTRI1, tUWIRE, tWIRE, tWAND, tWOR))
1002
      *kind = p_net_type();
1✔
1003
   else
1004
      *kind = V_NET_WIRE;
123✔
1005

1006
   *dt = p_data_type_or_implicit();
124✔
1007
}
124✔
1008

1009
static vlog_node_t p_var_data_type(void)
3✔
1010
{
1011
   // data_type | var data_type_or_implicit
1012

1013
   BEGIN("var data type");
6✔
1014

1015
   return p_data_type();
3✔
1016
}
1017

1018
static vlog_node_t p_variable_port_type(void)
3✔
1019
{
1020
   // var_data_type
1021

1022
   BEGIN("variable port type");
6✔
1023

1024
   return p_var_data_type();
3✔
1025
}
1026

1027
static void p_list_of_port_identifiers(vlog_node_t mod, v_port_kind_t kind,
89✔
1028
                                       vlog_node_t datatype)
1029
{
1030
   // port_identifier { unpacked_dimension }
1031
   //    { , port_identifier { unpacked_dimension } }
1032

1033
   BEGIN("list of port identifiers");
178✔
1034

1035
   do {
108✔
1036
      ident_t id, ext;
108✔
1037
      p_external_identifier(&id, &ext);
108✔
1038

1039
      vlog_node_t v = vlog_new(V_PORT_DECL);
108✔
1040
      vlog_set_subkind(v, kind);
108✔
1041
      vlog_set_ident(v, id);
108✔
1042
      vlog_set_ident2(v, ext);
108✔
1043
      vlog_set_type(v, datatype);
108✔
1044
      vlog_set_loc(v, &state.last_loc);
108✔
1045

1046
      vlog_add_decl(mod, v);
108✔
1047
      vlog_symtab_put(symtab, v);
108✔
1048

1049
      vlog_node_t ref = vlog_new(V_REF);
108✔
1050
      vlog_set_loc(ref, CURRENT_LOC);
108✔
1051
      vlog_set_ident(ref, id);
108✔
1052
      vlog_set_ref(ref, v);
108✔
1053

1054
      vlog_add_port(mod, ref);
108✔
1055
   } while (optional(tCOMMA));
108✔
1056
}
89✔
1057

1058
static void p_list_of_variable_port_identifiers(vlog_node_t mod,
3✔
1059
                                                v_port_kind_t kind,
1060
                                                vlog_node_t datatype)
1061
{
1062
   // port_identifier { variable_dimension } [ = constant_expression ]
1063
   //   { , port_identifier { variable_dimension } [ = constant_expression ] }
1064

1065
   BEGIN("list of variable port identifiers");
6✔
1066

1067
   do {
3✔
1068
      ident_t id, ext;
3✔
1069
      p_external_identifier(&id, &ext);
3✔
1070

1071
      vlog_node_t v = vlog_new(V_PORT_DECL);
3✔
1072
      vlog_set_subkind(v, kind);
3✔
1073
      vlog_set_ident(v, id);
3✔
1074
      vlog_set_ident2(v, ext);
3✔
1075
      vlog_set_type(v, datatype);
3✔
1076
      vlog_set_loc(v, &state.last_loc);
3✔
1077

1078
      vlog_add_decl(mod, v);
3✔
1079
      vlog_symtab_put(symtab, v);
3✔
1080

1081
      vlog_node_t reg = vlog_new(V_VAR_DECL);
3✔
1082
      vlog_set_loc(reg, vlog_loc(v));
3✔
1083
      vlog_set_ident(reg, id);
3✔
1084
      vlog_set_type(reg, datatype);
3✔
1085

1086
      vlog_add_decl(mod, reg);
3✔
1087
      vlog_symtab_put(symtab, reg);
3✔
1088

1089
      vlog_node_t ref = vlog_new(V_REF);
3✔
1090
      vlog_set_loc(ref, CURRENT_LOC);
3✔
1091
      vlog_set_ident(ref, id);
3✔
1092
      vlog_set_ref(ref, v);
3✔
1093

1094
      vlog_add_port(mod, ref);
3✔
1095
   } while (optional(tCOMMA));
3✔
1096
}
3✔
1097

1098
static void p_inout_declaration(vlog_node_t mod)
1✔
1099
{
1100
   // inout net_port_type list_of_port_identifiers
1101

1102
   BEGIN("inout declaration");
2✔
1103

1104
   consume(tINOUT);
1✔
1105

1106
   vlog_node_t dt;
1✔
1107
   vlog_net_kind_t kind;
1✔
1108
   p_net_port_type(&kind, &dt);
1✔
1109

1110
   p_list_of_port_identifiers(mod, V_PORT_INOUT, dt);
1✔
1111
}
1✔
1112

1113
static void p_input_declaration(vlog_node_t mod)
48✔
1114
{
1115
   // input net_port_type list_of_port_identifiers
1116
   //   | input variable_port_type list_of_variable_identifiers
1117

1118
   BEGIN("input declaration");
96✔
1119

1120
   consume(tINPUT);
48✔
1121

1122
   vlog_node_t dt;
48✔
1123
   vlog_net_kind_t kind;
48✔
1124
   switch (peek()) {
48✔
1125
   case tREG:
×
1126
      dt = p_variable_port_type();
×
1127
      p_list_of_variable_port_identifiers(mod, V_PORT_INPUT, dt);
×
1128
      break;
×
1129
   default:
48✔
1130
      p_net_port_type(&kind, &dt);
48✔
1131
      p_list_of_port_identifiers(mod, V_PORT_INPUT, dt);
48✔
1132
      break;
48✔
1133
   }
1134
}
48✔
1135

1136
static void p_output_declaration(vlog_node_t mod)
43✔
1137
{
1138
   // output net_port_type list_of_port_identifiers
1139
   //   | output variable_port_type list_of_variable_port_identifiers
1140

1141
   BEGIN("output declaration");
86✔
1142

1143
   consume(tOUTPUT);
43✔
1144

1145
   switch (peek()) {
43✔
1146
   case tREG:
3✔
1147
      {
1148
         vlog_node_t dt = p_variable_port_type();
3✔
1149
         p_list_of_variable_port_identifiers(mod, V_PORT_OUTPUT, dt);
3✔
1150
      }
1151
      break;
3✔
1152
   default:
40✔
1153
      {
1154
         vlog_node_t dt;
40✔
1155
         vlog_net_kind_t kind;
40✔
1156
         p_net_port_type(&kind, &dt);
40✔
1157
         p_list_of_port_identifiers(mod, V_PORT_OUTPUT, dt);
40✔
1158
      }
1159
      break;
40✔
1160
   }
1161
}
43✔
1162

1163
static void p_port_declaration(vlog_node_t mod)
92✔
1164
{
1165
   // { attribute_instance } inout_declaration
1166
   //   | { attribute_instance } input_declaration
1167
   //   | { attribute_instance } output_declaration
1168
   //   | { attribute_instance } ref_declaration
1169
   //   | { attribute_instance } interface_port_declaration
1170

1171
   BEGIN("port declaration");
184✔
1172

1173
   switch (peek()) {
92✔
1174
   case tINOUT: p_inout_declaration(mod); break;
1✔
1175
   case tINPUT: p_input_declaration(mod); break;
48✔
1176
   case tOUTPUT: p_output_declaration(mod); break;
43✔
1177
   default: should_not_reach_here();
1178
   }
1179
}
92✔
1180

1181
static vlog_node_t p_net_port_header(v_port_kind_t *dir, bool *isreg)
35✔
1182
{
1183
   // [ port_direction ] net_port_type
1184

1185
   BEGIN("net port header");
35✔
1186

1187
   if (optional(tINPUT)) {
35✔
1188
      *dir = V_PORT_INPUT;
17✔
1189
      *isreg = (peek() == tREG);
17✔
1190
   }
1191
   else if (optional(tINOUT)) {
18✔
1192
      *dir = V_PORT_INOUT;
×
1193
      *isreg = false;
×
1194
   }
1195
   else if (optional(tOUTPUT)) {
18✔
1196
      *dir = V_PORT_OUTPUT;
18✔
1197
      *isreg = (peek() == tREG);
18✔
1198
   }
1199

1200
   vlog_net_kind_t kind;
35✔
1201
   vlog_node_t dt;
35✔
1202
   p_net_port_type(&kind, &dt);
35✔
1203
   return dt;
35✔
1204
}
1205

1206
static void p_part_select_range(vlog_node_t ps)
31✔
1207
{
1208
   // constant_expression : constant_expression
1209
   //   | expression +: constant_expression
1210
   //   | expression -: constant_expression
1211

1212
   BEGIN("part select range");
62✔
1213

1214
   vlog_range_kind_t kind = V_RANGE_CONST;
31✔
1215
   switch (one_of(tCOLON, tINDEXPOS, tINDEXNEG)) {
31✔
1216
   case tINDEXPOS: kind = V_RANGE_POS; break;
1✔
1217
   case tINDEXNEG: kind = V_RANGE_NEG; break;
×
1218
   }
1219

1220
   vlog_set_subkind(ps, kind);
31✔
1221
   vlog_set_right(ps, p_constant_expression());
31✔
1222
}
31✔
1223

1224
static vlog_node_t p_select(ident_t id)
2,200✔
1225
{
1226
   // [ { . member_identifier bit_select } . member_identifier ]
1227
   //    { [ expression ] } [ [ part_select_range ] ]
1228

1229
   EXTEND("select");
4,400✔
1230

1231
   vlog_node_t prefix = vlog_new(V_REF);
2,200✔
1232
   vlog_set_ident(prefix, id);
2,200✔
1233
   vlog_set_loc(prefix, CURRENT_LOC);
2,200✔
1234

1235
   vlog_symtab_lookup(symtab, prefix);
2,200✔
1236

1237
    if (optional(tLSQUARE)) {
2,200✔
1238
       do {
235✔
1239
          vlog_node_t expr = p_expression();
235✔
1240
          if (scan(tCOLON, tINDEXPOS, tINDEXNEG)) {
235✔
1241
             vlog_node_t ps = vlog_new(V_PART_SELECT);
31✔
1242
             vlog_set_left(ps, expr);
31✔
1243
             vlog_set_value(ps, prefix);
31✔
1244

1245
             p_part_select_range(ps);
31✔
1246

1247
             consume(tRSQUARE);
31✔
1248

1249
             vlog_set_loc(ps, CURRENT_LOC);
31✔
1250
             return ps;
31✔
1251
          }
1252

1253
          if (vlog_kind(prefix) == V_BIT_SELECT)
204✔
1254
             vlog_add_param(prefix, expr);
60✔
1255
          else {
1256
             vlog_node_t bs = vlog_new(V_BIT_SELECT);
144✔
1257
             vlog_set_loc(bs, CURRENT_LOC);
144✔
1258
             vlog_set_value(bs, prefix);
144✔
1259
             vlog_add_param(bs, expr);
144✔
1260

1261
             prefix = bs;
144✔
1262
          }
1263

1264
          consume(tRSQUARE);
204✔
1265
       } while (optional(tLSQUARE));
204✔
1266
    }
1267

1268
    return prefix;
1269
}
1270

1271
static void p_list_of_arguments(vlog_node_t call)
613✔
1272
{
1273
   // [ expression ] { , [ expression ] } { , . identifier ( [ expression ] ) }
1274
   //    | . identifier ( [ expression ] ) { , . identifier ( [ expression ] ) }
1275

1276
   BEGIN("list of arguments");
1,226✔
1277

1278
   if (peek() != tRPAREN)
613✔
1279
      do {
1,162✔
1280
         if (peek() == tCOMMA) {
1,162✔
1281
            vlog_node_t v = vlog_new(V_EMPTY);
12✔
1282
            vlog_set_loc(v, &state.last_loc);
12✔
1283
            vlog_add_param(call, v);
12✔
1284
         }
1285
         else
1286
            vlog_add_param(call, p_expression());
1,150✔
1287
      } while (optional(tCOMMA));
1,162✔
1288
}
613✔
1289

1290
static vlog_node_t p_system_tf_call(vlog_kind_t kind)
900✔
1291
{
1292
   // system_tf_identifier [ ( list_of_arguments ) ]
1293

1294
   BEGIN("system task or function call");
900✔
1295

1296
   vlog_node_t v = vlog_new(kind);
900✔
1297
   vlog_set_ident(v, p_system_tf_identifier());
900✔
1298

1299
   if (optional(tLPAREN)) {
900✔
1300
      p_list_of_arguments(v);
601✔
1301
      consume(tRPAREN);
601✔
1302
   }
1303

1304
   vlog_set_loc(v, CURRENT_LOC);
900✔
1305
   return v;
900✔
1306
}
1307

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

1313
   BEGIN("task or function call");
12✔
1314

1315
   vlog_node_t v = vlog_new(kind);
12✔
1316
   vlog_set_ident(v, p_identifier());
12✔
1317

1318
   if (optional(tLPAREN)) {
12✔
1319
      p_list_of_arguments(v);
12✔
1320
      consume(tRPAREN);
12✔
1321
   }
1322

1323
   vlog_set_loc(v, CURRENT_LOC);
12✔
1324
   vlog_symtab_lookup(symtab, v);
12✔
1325
   return v;
12✔
1326
}
1327

1328
static vlog_node_t p_subroutine_call(vlog_kind_t kind)
912✔
1329
{
1330
   // tf_call | system_tf_call | method_call | [ std:: ] randomize_call
1331

1332
   BEGIN("subroutine call");
1,824✔
1333

1334
   if (peek() == tSYSTASK)
912✔
1335
      return p_system_tf_call(kind);
900✔
1336
   else
1337
      return p_tf_call(kind);
12✔
1338
}
1339

1340
static vlog_node_t p_mintypmax_expression(void)
47✔
1341
{
1342
   // expression | expression : expression : expression
1343

1344
   BEGIN("mintypmax expression");
94✔
1345

1346
   return p_expression();
47✔
1347
}
1348

1349
static vlog_node_t p_concatenation(vlog_node_t head)
20✔
1350
{
1351
   // { expression { , expression } }
1352

1353
   BEGIN_WITH_HEAD("concatenation", head);
20✔
1354

1355
   if (head == NULL) {
20✔
1356
      consume(tLBRACE);
6✔
1357
      head = p_expression();
6✔
1358
   }
1359

1360
   vlog_node_t v = vlog_new(V_CONCAT);
20✔
1361
   vlog_add_param(v, head);
20✔
1362

1363
   while (optional(tCOMMA))
34✔
1364
      vlog_add_param(v, p_expression());
14✔
1365

1366
   consume(tRBRACE);
20✔
1367

1368
   vlog_set_loc(v, CURRENT_LOC);
20✔
1369
   return v;
20✔
1370
}
1371

1372
static vlog_node_t p_multiple_concatenation(vlog_node_t head)
6✔
1373
{
1374
   // { expression concatenation }
1375

1376
   BEGIN_WITH_HEAD("multiple concatenation", head);
6✔
1377

1378
   vlog_node_t v = p_concatenation(NULL);
6✔
1379
   vlog_set_value(v, head);
6✔
1380

1381
   consume(tRBRACE);
6✔
1382

1383
   vlog_set_loc(v, CURRENT_LOC);
6✔
1384
   return v;
6✔
1385
}
1386

1387
static vlog_node_t p_primary(void)
3,868✔
1388
{
1389
   // primary_literal | empty_queue
1390
   // | [ class_qualifier | package_scope ] hierarchical_identifier select
1391
   // | concatenation [ [ range_expression ] ]
1392
   // | multiple_concatenation [ [ range_expression ] ]
1393
   // | function_subroutine_call
1394
   // | let_expression | ( mintypmax_expression ) | cast
1395
   // | assignment_pattern_expression | streaming_concatenation
1396
   // | sequence_method_call | this | $ | null
1397

1398
   BEGIN("primary");
7,736✔
1399

1400
   switch (peek()) {
3,868✔
1401
   case tID:
1,415✔
1402
      if (peek_nth(2) == tLPAREN)
1,415✔
1403
         return p_subroutine_call(V_USER_FCALL);
8✔
1404
      else
1405
         return p_select(p_identifier());
1,407✔
1406
   case tSTRING:
2,371✔
1407
   case tNUMBER:
1408
   case tUNSIGNED:
1409
   case tREAL:
1410
      return p_primary_literal();
2,371✔
1411
   case tSYSTASK:
53✔
1412
      return p_subroutine_call(V_SYS_FCALL);
53✔
1413
   case tLPAREN:
9✔
1414
      {
1415
         consume(tLPAREN);
9✔
1416
         vlog_node_t expr = p_mintypmax_expression();
9✔
1417
         consume(tRPAREN);
9✔
1418
         return expr;
9✔
1419
      }
1420
   case tLBRACE:
20✔
1421
      {
1422
         consume(tLBRACE);
20✔
1423

1424
         vlog_node_t head = p_expression();
20✔
1425
         if (peek() == tLBRACE)
20✔
1426
            return p_multiple_concatenation(head);
6✔
1427
         else
1428
            return p_concatenation(head);
14✔
1429
      }
1430
   default:
×
1431
      one_of(tID, tSTRING, tNUMBER, tUNSIGNED, tREAL, tSYSTASK, tLPAREN,
×
1432
             tLBRACE);
1433
      return p_select(error_marker());
×
1434
   }
1435
}
1436

1437
static vlog_binary_t p_binary_operator(void)
516✔
1438
{
1439
   // + | - | * | / | % | == | != | === | !== | ==? | !=? | && | ||
1440
   //  | ** | < | <= | > | >= | & | | | ^ | ^~ | ~^ | >> | <<
1441
   //  | >>> | <<< | -> | <->
1442

1443
   BEGIN("binary operator");
1,032✔
1444

1445
   switch (one_of(tBAR, tPLUS, tAMP, tCASEEQ, tCASENEQ, tLOGOR,
516✔
1446
                  tLOGEQ, tLOGNEQ, tDBLAMP, tSHIFTLL, tSHIFTRL,
1447
                  tSHIFTLA, tSHIFTRA, tLT, tGT, tLE, tGE, tMINUS,
1448
                  tTIMES, tOVER, tPERCENT, tPOWER, tCARET, tTILDECARET)) {
1449
   case tBAR:        return V_BINARY_OR;
1450
   case tAMP:        return V_BINARY_AND;
28✔
1451
   case tCASEEQ:     return V_BINARY_CASE_EQ;
38✔
1452
   case tCASENEQ:    return V_BINARY_CASE_NEQ;
241✔
1453
   case tLOGEQ:      return V_BINARY_LOG_EQ;
27✔
1454
   case tLOGNEQ:     return V_BINARY_LOG_NEQ;
×
1455
   case tLOGOR:      return V_BINARY_LOG_OR;
34✔
1456
   case tDBLAMP:     return V_BINARY_LOG_AND;
18✔
1457
   case tSHIFTLL:    return V_BINARY_SHIFT_LL;
5✔
1458
   case tSHIFTRL:    return V_BINARY_SHIFT_RL;
1✔
1459
   case tSHIFTLA:    return V_BINARY_SHIFT_LA;
1✔
1460
   case tSHIFTRA:    return V_BINARY_SHIFT_RA;
1✔
1461
   case tLT:         return V_BINARY_LT;
16✔
1462
   case tGT:         return V_BINARY_GT;
13✔
1463
   case tLE:         return V_BINARY_LEQ;
8✔
1464
   case tGE:         return V_BINARY_GEQ;
8✔
1465
   case tMINUS:      return V_BINARY_MINUS;
16✔
1466
   case tTIMES:      return V_BINARY_TIMES;
3✔
1467
   case tOVER:       return V_BINARY_DIVIDE;
1✔
1468
   case tPERCENT:    return V_BINARY_MOD;
1✔
1469
   case tPOWER:      return V_BINARY_EXP;
1✔
1470
   case tCARET:      return V_BINARY_XOR;
1✔
1471
   case tTILDECARET: return V_BINARY_XNOR;
2✔
1472
   case tPLUS:
36✔
1473
   default:          return V_BINARY_PLUS;
36✔
1474
   }
1475
}
1476

1477
static vlog_unary_t p_unary_operator(void)
65✔
1478
{
1479
   // + | - | ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~
1480

1481
   BEGIN("unary operator");
130✔
1482

1483
   switch (one_of(tMINUS, tPLUS, tTILDE, tBANG, tAMP, tBAR, tCARET)) {
65✔
1484
   case tMINUS: return V_UNARY_NEG;
1485
   case tTILDE: return V_UNARY_BITNEG;
28✔
1486
   case tBANG: return V_UNARY_NOT;
24✔
1487
   case tAMP: return V_UNARY_AND;
1✔
1488
   case tBAR: return V_UNARY_OR;
5✔
1489
   case tCARET: return V_UNARY_XOR;
1✔
1490
   case tPLUS:
1✔
1491
   default: return V_UNARY_IDENTITY;
1✔
1492
   }
1493
}
1494

1495
static vlog_incdec_t p_inc_or_dec_operator(void)
9✔
1496
{
1497
   // ++ | --
1498

1499
   BEGIN("inc or dec operator");
18✔
1500

1501
   switch (one_of(tPLUSPLUS, tMINUSMINUS)) {
9✔
1502
   case tMINUSMINUS: return V_INCDEC_MINUS;
1503
   case tPLUSPLUS:
8✔
1504
   default: return V_INCDEC_PLUS;
8✔
1505
   }
1506
}
1507

1508
static vlog_node_t p_inc_or_dec_expression(vlog_node_t head)
8✔
1509
{
1510
   // inc_or_dec_operator { attribute_instance } variable_lvalue
1511
   //   | variable_lvalue { attribute_instance } inc_or_dec_operator
1512

1513
   BEGIN_WITH_HEAD("inc or dec expression", head);
8✔
1514

1515
   vlog_node_t v = vlog_new(head ? V_POSTFIX : V_PREFIX);
14✔
1516
   vlog_set_subkind(v, p_inc_or_dec_operator());
8✔
1517
   vlog_set_target(v, head ?: p_variable_lvalue());
8✔
1518

1519
   vlog_set_loc(v, CURRENT_LOC);
8✔
1520
   return v;
8✔
1521
}
1522

1523
static vlog_node_t p_nonbinary_expression(void)
3,874✔
1524
{
1525
   // primary | unary_operator { attribute_instance } primary
1526
   //   | inc_or_dec_expression | ( operator_assignment )
1527
   //   | conditional_expression | inside_expression | tagged_union_expression
1528

1529
   switch (peek()) {
3,874✔
1530
   case tID:
3,803✔
1531
   case tSTRING:
1532
   case tNUMBER:
1533
   case tUNSIGNED:
1534
   case tREAL:
1535
   case tSYSTASK:
1536
   case tLPAREN:
1537
   case tLBRACE:
1538
      return p_primary();
3,803✔
1539
   case tMINUS:
65✔
1540
   case tPLUS:
1541
   case tTILDE:
1542
   case tBANG:
1543
   case tAMP:
1544
   case tBAR:
1545
   case tCARET:
1546
      {
1547
         vlog_node_t v = vlog_new(V_UNARY);
65✔
1548
         vlog_set_subkind(v, p_unary_operator());
65✔
1549
         vlog_set_value(v, p_primary());
65✔
1550
         vlog_set_loc(v, CURRENT_LOC);
65✔
1551
         return v;
65✔
1552
      }
1553
   case tPLUSPLUS:
5✔
1554
   case tMINUSMINUS:
1555
      return p_inc_or_dec_expression(NULL);
5✔
1556
   default:
1✔
1557
      one_of(tID, tSTRING, tNUMBER, tUNSIGNED, tREAL, tSYSTASK, tLPAREN,
1✔
1558
             tLBRACE, tMINUS, tTILDE, tBANG, tAMP, tBAR, tCARET, tPLUSPLUS,
1559
             tMINUSMINUS);
1560
      return p_select(error_marker());
1✔
1561
   }
1562
}
1563

1564
static vlog_node_t p_conditional_expression(vlog_node_t head)
6✔
1565
{
1566
   // cond_predicate ? { attribute_instance } expression : expression
1567

1568
   BEGIN_WITH_HEAD("conditional expression", head);
6✔
1569

1570
   vlog_node_t v = vlog_new(V_COND_EXPR);
6✔
1571
   vlog_set_value(v, head);
6✔
1572

1573
   consume(tQUESTION);
6✔
1574

1575
   optional_attributes();
6✔
1576

1577
   vlog_set_left(v, p_expression());
6✔
1578

1579
   consume(tCOLON);
6✔
1580

1581
   vlog_set_right(v, p_expression());
6✔
1582

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

1587
static bool peek_binary_operator(int *prec)
4,508✔
1588
{
1589
   // See LRM 1800-2017 section 11.3.2 for operator precedence table
1590

1591
   switch (peek()) {
4,508✔
1592
   case tPOWER:      *prec = 12; return true;
1✔
1593
   case tTIMES:
8✔
1594
   case tOVER:
1595
   case tPERCENT:    *prec = 11; return true;
8✔
1596
   case tPLUS:
56✔
1597
   case tMINUS:      *prec = 10; return true;
56✔
1598
   case tSHIFTLL:
8✔
1599
   case tSHIFTRL:
1600
   case tSHIFTLA:
1601
   case tSHIFTRA:    *prec = 9;  return true;
8✔
1602
   case tLT:
45✔
1603
   case tGT:
1604
   case tLE:
1605
   case tGE:         *prec = 8;  return true;
45✔
1606
   case tCASEEQ:
358✔
1607
   case tCASENEQ:
1608
   case tLOGEQ:
1609
   case tLOGNEQ:     *prec = 7;  return true;
358✔
1610
   case tAMP:        *prec = 6;  return true;
30✔
1611
   case tTILDECARET:
3✔
1612
   case tCARET:      *prec = 5;  return true;
3✔
1613
   case tBAR:        *prec = 4;  return true;
17✔
1614
   case tDBLAMP:     *prec = 3;  return true;
42✔
1615
   case tLOGOR:      *prec = 2;  return true;
75✔
1616
   case tQUESTION:   *prec = 1;  return true;
10✔
1617
   default:
1618
      return false;
1619
   }
1620
}
1621

1622
static vlog_node_t p_binary_expression(vlog_node_t lhs, int min_prec)
3,414✔
1623
{
1624
   // Precedence climbing method, see
1625
   //    https://en.wikipedia.org/wiki/Operator-precedence_parser
1626

1627
   int prec1;
3,414✔
1628
   while (peek_binary_operator(&prec1) && prec1 >= min_prec) {
3,936✔
1629
      if (peek() == tQUESTION)
522✔
1630
         lhs = p_conditional_expression(lhs);
6✔
1631
      else {
1632
         vlog_node_t v = vlog_new(V_BINARY);
516✔
1633
         vlog_set_subkind(v, p_binary_operator());
516✔
1634
         vlog_set_left(v, lhs);
516✔
1635

1636
         vlog_node_t rhs = p_nonbinary_expression();
516✔
1637

1638
         int prec2;
516✔
1639
         while (peek_binary_operator(&prec2) && prec2 > prec1)
572✔
1640
            rhs = p_binary_expression(rhs, prec1 + (prec2 > prec1));
56✔
1641

1642
         vlog_set_right(v, rhs);
516✔
1643
         vlog_set_loc(v, CURRENT_LOC);
516✔
1644
         lhs = v;
516✔
1645
      }
1646
   }
1647

1648
   return lhs;
3,414✔
1649
}
1650

1651
static vlog_node_t p_expression(void)
3,358✔
1652
{
1653
   // primary | unary_operator { attribute_instance } primary
1654
   //   | inc_or_dec_expression | ( operator_assignment )
1655
   //   | expression binary_operator { attribute_instance } expression
1656
   //   | conditional_expression | inside_expression | tagged_union_expression
1657

1658
   BEGIN("expression");
6,716✔
1659

1660
   vlog_node_t head = p_nonbinary_expression();
3,358✔
1661
   return p_binary_expression(head, 0);
3,358✔
1662
}
1663

1664
static void p_event_expression(vlog_node_t ctrl)
105✔
1665
{
1666
   // [ edge_identifier ] expression [ iff expression ]
1667
   //   | sequence_instance [ iff expression ]
1668
   //   | event_expression or event_expression
1669
   //   | event_expression , event_expression
1670
   //   | ( event_expression )
1671

1672
   BEGIN("event expression");
210✔
1673

1674
   do {
131✔
1675
      if (optional(tLPAREN)) {
131✔
1676
         p_event_expression(ctrl);
1✔
1677
         consume(tRPAREN);
1✔
1678
      }
1679
      else {
1680
         vlog_node_t v = vlog_new(V_EVENT);
130✔
1681

1682
         if (optional(tPOSEDGE))
130✔
1683
            vlog_set_subkind(v, V_EVENT_POSEDGE);
29✔
1684
         else if (optional(tNEGEDGE))
101✔
1685
            vlog_set_subkind(v, V_EVENT_NEGEDGE);
4✔
1686
         else
1687
            vlog_set_subkind(v, V_EVENT_LEVEL);
97✔
1688

1689
         vlog_set_value(v, p_expression());
130✔
1690
         vlog_set_loc(v, CURRENT_LOC);
130✔
1691

1692
         vlog_add_param(ctrl, v);
130✔
1693
      }
1694
   } while (optional(tOR) || optional(tCOMMA));
131✔
1695
}
105✔
1696

1697
static vlog_node_t p_cond_predicate(void)
294✔
1698
{
1699
   // expression_or_cond_pattern { &&& expression_or_cond_pattern }
1700

1701
   BEGIN("cond predicate");
588✔
1702

1703
   return p_expression();
294✔
1704
}
1705

1706
static vlog_node_t p_event_control(void)
117✔
1707
{
1708
   // @ hierarchical_event_identifier | @ ( event_expression )
1709
   //    | @* | @ (*) | @ ps_or_hierarchical_sequence_identifier
1710

1711
   BEGIN("event control");
117✔
1712

1713
   consume(tAT);
117✔
1714

1715
   vlog_node_t v = vlog_new(V_EVENT_CONTROL);
117✔
1716

1717
   switch (one_of(tLPAREN, tTIMES, tPARENSTAR)) {
117✔
1718
   case tLPAREN:
104✔
1719
      p_event_expression(v);
104✔
1720
      consume(tRPAREN);
104✔
1721
      break;
104✔
1722
   case tTIMES:
1723
   case tPARENSTAR:
1724
      break;
1725
   }
1726

1727
   vlog_set_loc(v, CURRENT_LOC);
117✔
1728
   return v;
117✔
1729
}
1730

1731
static vlog_node_t p_delay_value(void)
339✔
1732
{
1733
   // unsigned_number | real_number | ps_identifier | time_literal | 1step
1734

1735
   BEGIN("delay value");
678✔
1736

1737
   return p_unsigned_number();
339✔
1738
}
1739

1740
static vlog_node_t p_delay_control(void)
335✔
1741
{
1742
   // # delay_value | # ( mintypmax_expression )
1743

1744
   BEGIN("delay control");
335✔
1745

1746
   consume(tHASH);
335✔
1747

1748
   vlog_node_t v = vlog_new(V_DELAY_CONTROL);
335✔
1749

1750
   if (peek() != tLPAREN)
335✔
1751
      vlog_set_value(v, p_delay_value());
335✔
1752
   else
NEW
1753
      vlog_set_value(v, p_mintypmax_expression());
×
1754

1755
   vlog_set_loc(v, CURRENT_LOC);
335✔
1756
   return v;
335✔
1757
}
1758

1759
static void p_delay3(void)
7✔
1760
{
1761
   // # delay_value | # ( mintypmax_expression [ , mintypmax_expression [ , mintypmax_expression ] ] )
1762

1763
   BEGIN("delay3");
14✔
1764

1765
   consume(tHASH);
7✔
1766

1767
   if (peek() != tLPAREN) {
7✔
1768
      p_delay_value();
3✔
1769
   } else {
1770
      consume(tLPAREN);
4✔
1771

1772
      int expr_cnt = 0;
4✔
1773
      do {
12✔
1774
         (void)p_mintypmax_expression();
12✔
1775
         expr_cnt++;
12✔
1776
      } while (optional(tCOMMA) && (expr_cnt < 3));
12✔
1777

1778
      consume(tRPAREN);
4✔
1779
   }
1780
}
7✔
1781

1782
static vlog_node_t p_delay_or_event_control(void)
50✔
1783
{
1784
   // delay_control | event_control | repeat ( expression ) event_control
1785

1786
   BEGIN("delay or event control");
100✔
1787

1788
   return p_delay_control();
50✔
1789
}
1790

1791
static vlog_node_t p_variable_lvalue(void)
630✔
1792
{
1793
   // [ implicit_class_handle . | package_scope ]
1794
   //      hierarchical_variable_identifier select
1795
   //   | { variable_lvalue { , variable_lvalue } }
1796
   //   | [ assignment_pattern_expression_type ]
1797
   //      assignment_pattern_variable_lvalue
1798
   //   | streaming_concatenation
1799

1800
   BEGIN("variable lvalue");
630✔
1801

1802
   ident_t id = p_identifier();
630✔
1803
   vlog_node_t v = p_select(id);
630✔
1804

1805
   vlog_set_loc(v, CURRENT_LOC);
630✔
1806
   return v;
630✔
1807
}
1808

1809
static vlog_node_t p_net_lvalue(void)
165✔
1810
{
1811
   // ps_or_hierarchical_net_identifier constant_select
1812
   //   | { net_lvalue { , net_lvalue } }
1813
   //   | [ assignment_pattern_expression_type ] assignment_pattern_net_lvalue
1814

1815
   BEGIN("net lvalue");
330✔
1816

1817
   if (optional(tLBRACE)) {
165✔
1818
      vlog_node_t v = vlog_new(V_CONCAT);
3✔
1819

1820
      do {
6✔
1821
         vlog_add_param(v, p_net_lvalue());
6✔
1822
      } while (optional(tCOMMA));
6✔
1823

1824
      consume(tRBRACE);
3✔
1825

1826
      vlog_set_loc(v, CURRENT_LOC);
3✔
1827
      return v;
3✔
1828
   }
1829
   else {
1830
      ident_t id = p_identifier();
162✔
1831
      vlog_node_t v = p_constant_select(id);
162✔
1832

1833
      vlog_set_loc(v, CURRENT_LOC);
162✔
1834
      return v;
162✔
1835
   }
1836
}
1837

1838
static vlog_node_t p_operator_assignment(vlog_node_t lhs)
456✔
1839
{
1840
   // variable_lvalue assignment_operator expression
1841

1842
   BEGIN_WITH_HEAD("operator assignment", lhs);
456✔
1843

1844
   consume(tEQ);
456✔
1845

1846
   vlog_node_t v = vlog_new(V_BASSIGN);
456✔
1847
   vlog_set_target(v, lhs);
456✔
1848

1849
   vlog_set_value(v, p_expression());
456✔
1850

1851
   vlog_set_loc(v, CURRENT_LOC);
456✔
1852
   return v;
456✔
1853
}
1854

1855
static vlog_node_t p_blocking_assignment(vlog_node_t lhs)
484✔
1856
{
1857
   // variable_lvalue = delay_or_event_control expression
1858
   //   | nonrange_variable_lvalue = dynamic_array_new
1859
   //   | [ implicit_class_handle . | class_scope | package_scope ]
1860
   //         hierarchical_variable_identifier select != class_new
1861
   //   | operator_assignment
1862

1863
   BEGIN_WITH_HEAD("blocking assignment", lhs);
968✔
1864

1865
   switch (peek_nth(2)) {
484✔
1866
   case tHASH:
33✔
1867
   case tAT:
1868
      {
1869
         consume(tEQ);
33✔
1870

1871
         vlog_node_t v = vlog_new(V_BASSIGN);
33✔
1872
         vlog_set_target(v, lhs);
33✔
1873
         vlog_set_delay(v, p_delay_or_event_control());
33✔
1874
         vlog_set_value(v, p_expression());
33✔
1875

1876
         vlog_set_loc(v, CURRENT_LOC);
33✔
1877
         return v;
33✔
1878
      }
1879
   default:
451✔
1880
      return p_operator_assignment(lhs);
451✔
1881
   }
1882
}
1883

1884
static vlog_node_t p_nonblocking_assignment(vlog_node_t lhs)
127✔
1885
{
1886
   // variable_lvalue <= [ delay_or_event_control ] expression
1887

1888
   BEGIN_WITH_HEAD("non-blocking assignment", lhs);
127✔
1889

1890
   consume(tLE);
127✔
1891

1892
   vlog_node_t v = vlog_new(V_NBASSIGN);
127✔
1893
   vlog_set_target(v, lhs);
127✔
1894

1895
   if (scan(tHASH, tAT))
127✔
1896
      vlog_set_delay(v, p_delay_or_event_control());
17✔
1897

1898
   vlog_set_value(v, p_expression());
127✔
1899

1900
   vlog_set_loc(v, CURRENT_LOC);
127✔
1901
   return v;
127✔
1902
}
1903

1904
static vlog_node_t p_procedural_timing_control(void)
402✔
1905
{
1906
   // delay_control | event_control | cycle_delay
1907

1908
   BEGIN("procedural timing control");
804✔
1909

1910
   switch (peek()) {
402✔
1911
   case tAT:
117✔
1912
      return p_event_control();
117✔
1913
   case tHASH:
285✔
1914
      return p_delay_control();
285✔
1915
   default:
×
1916
      should_not_reach_here();
1917
   }
1918
}
1919

1920
static vlog_node_t p_procedural_timing_control_statement(void)
402✔
1921
{
1922
   // procedural_timing_control statement_or_null
1923

1924
   BEGIN("procedural timing control statement");
402✔
1925

1926
   vlog_node_t v = vlog_new(V_TIMING);
402✔
1927
   vlog_set_value(v, p_procedural_timing_control());
402✔
1928

1929
   vlog_node_t s = p_statement_or_null();
402✔
1930
   if (s != NULL)
402✔
1931
      vlog_add_stmt(v, s);
274✔
1932

1933
   vlog_set_loc(v, CURRENT_LOC);
402✔
1934
   return v;
402✔
1935
}
1936

1937
static vlog_node_t p_seq_block(void)
433✔
1938
{
1939
   // begin [ : block_identifier ] { block_item_declaration }
1940
   //   { statement_or_null } end [ : block_identifier ]
1941

1942
   BEGIN("sequential block");
433✔
1943

1944
   consume(tBEGIN);
433✔
1945

1946
   vlog_node_t v = vlog_new(V_BLOCK);
433✔
1947
   vlog_set_loc(v, CURRENT_LOC);
433✔
1948

1949
   vlog_symtab_push(symtab, v);
433✔
1950

1951
   if (optional(tCOLON))
433✔
1952
      vlog_set_ident(v, p_identifier());
4✔
1953

1954
   skip_over_attributes();
433✔
1955

1956
   while (scan(tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM, tSVINT, tINTEGER,
435✔
1957
               tSVREAL, tSHORTREAL, tREALTIME, tBIT, tLOGIC)) {
1958
      p_block_item_declaration(v);
2✔
1959
      skip_over_attributes();
2✔
1960
   }
1961

1962
   while (not_at_token(tEND)) {
2,059✔
1963
      vlog_node_t s = p_statement_or_null();
1,626✔
1964
      if (s != NULL)
1,626✔
1965
         vlog_add_stmt(v, s);
1,626✔
1966
   }
1967

1968
   vlog_symtab_pop(symtab);
433✔
1969

1970
   consume(tEND);
433✔
1971

1972
   if (optional(tCOLON)) {
433✔
1973
      ident_t name = p_identifier();
3✔
1974
      if (!vlog_has_ident(v))
3✔
1975
         parse_error(&state.last_loc, "initial block does not have a label");
1✔
1976
      else if (name != vlog_ident(v))
2✔
1977
         parse_error(&state.last_loc, "'%s' does not match label '%s'",
1✔
1978
                     istr(name), istr(vlog_ident(v)));
1979
   }
1980

1981
   return v;
433✔
1982
}
1983

1984
static vlog_node_t p_par_block(void)
5✔
1985
{
1986
   // fork [ : block_identifier ] { block_item_declaration }
1987
   //   { statement_or_null } join_keyword [ : block_identifier ]
1988

1989
   BEGIN("parallel block");
5✔
1990

1991
   consume(tFORK);
5✔
1992

1993
   vlog_node_t v = vlog_new(V_FORK);
5✔
1994
   vlog_set_loc(v, CURRENT_LOC);
5✔
1995

1996
   vlog_symtab_push(symtab, v);
5✔
1997

1998
   if (optional(tCOLON))
5✔
1999
      vlog_set_ident(v, p_identifier());
3✔
2000

2001
   skip_over_attributes();
5✔
2002

2003
   while (scan(tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM, tSVINT, tINTEGER,
7✔
2004
               tSVREAL, tSHORTREAL, tREALTIME, tBIT, tLOGIC)) {
2005
      p_block_item_declaration(v);
2✔
2006
      skip_over_attributes();
2✔
2007
   }
2008

2009
   while (not_at_token(tJOIN)) {
10✔
2010
      vlog_node_t s = p_statement_or_null();
5✔
2011
      if (s != NULL)
5✔
2012
         vlog_add_stmt(v, s);
5✔
2013
   }
2014

2015
   vlog_symtab_pop(symtab);
5✔
2016

2017
   consume(tJOIN);
5✔
2018

2019
   if (optional(tCOLON)) {
5✔
2020
      ident_t name = p_identifier();
3✔
2021
      if (!vlog_has_ident(v))
3✔
2022
         parse_error(&state.last_loc, "fork block does not have a label");
1✔
2023
      else if (name != vlog_ident(v))
2✔
2024
         parse_error(&state.last_loc, "'%s' does not match label '%s'",
1✔
2025
                     istr(name), istr(vlog_ident(v)));
2026
   }
2027

2028
   return v;
5✔
2029
}
2030

2031
static vlog_node_t p_subroutine_call_statement(void)
851✔
2032
{
2033
   // subroutine_call ; | void ' ( function_subroutine_call ) ;
2034

2035
   BEGIN("subroutine call statement");
851✔
2036

2037
   vlog_node_t v;
851✔
2038
   switch (peek()) {
851✔
2039
   case tSYSTASK:
847✔
2040
      v = p_subroutine_call(V_SYS_TCALL);
847✔
2041
      break;
847✔
2042
   case tVOID:
1✔
2043
      {
2044
         consume(tVOID);
1✔
2045
         consume(tTICK);
1✔
2046
         consume(tLPAREN);
1✔
2047

2048
         const vlog_kind_t kind =
2✔
2049
            peek() == tSYSTASK ? V_SYS_FCALL : V_USER_FCALL;
1✔
2050

2051
         v = vlog_new(V_VOID_CALL);
1✔
2052
         vlog_set_value(v, p_subroutine_call(kind));
1✔
2053

2054
         consume(tRPAREN);
1✔
2055
      }
2056
      break;
1✔
2057
   case tID:
3✔
2058
   default:
2059
      v = p_subroutine_call(V_USER_TCALL);
3✔
2060
      break;
3✔
2061
   }
2062

2063
   consume(tSEMI);
851✔
2064

2065
   vlog_set_loc(v, CURRENT_LOC);
851✔
2066
   return v;
851✔
2067
}
2068

2069
static vlog_node_t p_conditional_statement(void)
285✔
2070
{
2071
   // [ unique_priority ] if ( cond_predicate ) statement_or_null
2072
   //     { else if ( cond_predicate ) statement_or_null }
2073
   //     [ else statement_or_null ]
2074

2075
   BEGIN("conditional statement");
285✔
2076

2077
   vlog_node_t v = vlog_new(V_IF);
285✔
2078

2079
   consume(tIF);
285✔
2080
   consume(tLPAREN);
285✔
2081

2082
   vlog_node_t c0 = vlog_new(V_COND);
285✔
2083
   vlog_set_value(c0, p_cond_predicate());
285✔
2084
   vlog_add_cond(v, c0);
285✔
2085

2086
   consume(tRPAREN);
285✔
2087

2088
   vlog_node_t s0 = p_statement_or_null();
285✔
2089
   if (s0 != NULL)
285✔
2090
      vlog_add_stmt(c0, s0);
280✔
2091

2092
   bool stop = false;
2093
   while (!stop && optional(tELSE)) {
360✔
2094
      vlog_node_t c = vlog_new(V_COND);
75✔
2095
      vlog_add_cond(v, c);
75✔
2096

2097
      if (optional(tIF)) {
75✔
2098
         consume(tLPAREN);
9✔
2099
         vlog_set_value(c, p_cond_predicate());
9✔
2100
         consume(tRPAREN);
9✔
2101
      }
2102
      else
2103
         stop = true;
2104

2105
      vlog_node_t s = p_statement_or_null();
75✔
2106
      if (s != NULL)
75✔
2107
         vlog_add_stmt(c, s);
74✔
2108
   }
2109

2110
   vlog_set_loc(v, CURRENT_LOC);
285✔
2111
   return v;
285✔
2112
}
2113

2114
static vlog_node_t p_variable_assignment(vlog_kind_t kind)
6✔
2115
{
2116
   // variable_lvalue = expression
2117

2118
   BEGIN("variable assignment");
6✔
2119

2120
   vlog_node_t v = vlog_new(kind);
6✔
2121
   vlog_set_target(v, p_variable_lvalue());
6✔
2122

2123
   consume(tEQ);
6✔
2124

2125
   vlog_set_value(v, p_expression());
6✔
2126

2127
   vlog_set_loc(v, CURRENT_LOC);
6✔
2128
   return v;
6✔
2129
}
2130

2131
static void p_list_of_variable_assignments(vlog_node_t parent)
6✔
2132
{
2133
   // variable_assignment { , variable_assignment }
2134

2135
   BEGIN("list of variable assignments");
12✔
2136

2137
   do {
6✔
2138
      vlog_node_t v = p_variable_assignment(V_BASSIGN);
6✔
2139
      vlog_add_stmt(parent, v);
6✔
2140
   } while (optional(tCOMMA));
6✔
2141
}
6✔
2142

2143
static void p_for_variable_declaration(vlog_node_t parent)
2✔
2144
{
2145
   // [ var ] data_type variable_identifier = expression
2146
   //   { , variable_identifier = expression }
2147

2148
   BEGIN("for variable declaration");
4✔
2149

2150
   optional(tVAR);
2✔
2151

2152
   vlog_node_t dt = p_data_type();
2✔
2153

2154
   do {
2✔
2155
      vlog_node_t v = vlog_new(V_VAR_DECL);
2✔
2156
      vlog_set_ident(v, p_identifier());
2✔
2157
      vlog_set_type(v, dt);
2✔
2158

2159
      consume(tEQ);
2✔
2160

2161
      vlog_set_value(v, p_expression());
2✔
2162

2163
      vlog_set_loc(v, CURRENT_LOC);
2✔
2164
      vlog_add_decl(parent, v);
2✔
2165

2166
      vlog_symtab_put(symtab, v);
2✔
2167
   } while (optional(tCOMMA));
2✔
2168
}
2✔
2169

2170
static vlog_node_t p_for_initialization(void)
8✔
2171
{
2172
   // list_of_variable_assignments
2173
   //   | for_variable_declaration { , for_variable_declaration }
2174

2175
   BEGIN("for initialization");
8✔
2176

2177
   vlog_node_t v = vlog_new(V_FOR_INIT);
8✔
2178

2179
   if (scan(tREG, tSTRUCT, tUNION, tENUM, tSVINT, tINTEGER, tSVREAL,
8✔
2180
            tSHORTREAL, tREALTIME, tLOGIC, tVAR)) {
2181
      do {
2✔
2182
         p_for_variable_declaration(v);
2✔
2183
      } while (optional(tCOMMA));
2✔
2184
   }
2185
   else
2186
      p_list_of_variable_assignments(v);
6✔
2187

2188
   vlog_set_loc(v, CURRENT_LOC);
8✔
2189
   return v;
8✔
2190
}
2191

2192
static vlog_node_t p_for_step(void)
8✔
2193
{
2194
   // operator_assignment | inc_or_dec_expression | function_subroutine_call
2195

2196
   BEGIN("for step");
8✔
2197

2198
   vlog_node_t v = vlog_new(V_FOR_STEP);
8✔
2199

2200
   switch (peek()) {
8✔
2201
   case tPLUSPLUS:
1✔
2202
   case tMINUSMINUS:
2203
      vlog_add_stmt(v, p_inc_or_dec_expression(NULL));
1✔
2204
      break;
1✔
2205
   default:
7✔
2206
      {
2207
         vlog_node_t head = p_variable_lvalue();
7✔
2208

2209
         switch (peek()) {
7✔
2210
         case tPLUSPLUS:
2✔
2211
         case tMINUSMINUS:
2212
            vlog_add_stmt(v, p_inc_or_dec_expression(head));
2✔
2213
            break;
2✔
2214
         default:
5✔
2215
            vlog_add_stmt(v, p_operator_assignment(head));
5✔
2216
            break;
5✔
2217
         }
2218
      }
2219
      break;
2220
   }
2221

2222
   vlog_set_loc(v, CURRENT_LOC);
8✔
2223
   return v;
8✔
2224
}
2225

2226
static vlog_node_t p_loop_statement(void)
20✔
2227
{
2228
   // forever statement_or_null
2229
   //   | repeat ( expression ) statement_or_null
2230
   //   | while ( expression ) statement_or_null
2231
   //   | for ( [ for_initialization ] ; [ expression ] ; [ for_step ] )
2232
   //       statement_or_null
2233
   //   | do statement_or_null while ( expression ) ;
2234
   //   | foreach ( ps_or_hierarchical_array_identifier [ loop_variables ] )
2235
   //       statement
2236

2237
   BEGIN("loop statement");
40✔
2238

2239
   switch (one_of(tFOREVER, tWHILE, tREPEAT, tDO, tFOR)) {
20✔
2240
   case tFOREVER:
5✔
2241
      {
2242
         vlog_node_t v = vlog_new(V_FOREVER);
5✔
2243

2244
         vlog_node_t s = p_statement_or_null();
5✔
2245
         if (s != NULL)
5✔
2246
            vlog_add_stmt(v, s);
5✔
2247

2248
         vlog_set_loc(v, CURRENT_LOC);
5✔
2249
         return v;
5✔
2250
      }
2251

2252
   case tWHILE:
2✔
2253
      {
2254
         vlog_node_t v = vlog_new(V_WHILE);
2✔
2255

2256
         consume(tLPAREN);
2✔
2257
         vlog_set_value(v, p_expression());
2✔
2258
         consume(tRPAREN);
2✔
2259

2260
         vlog_node_t s = p_statement_or_null();
2✔
2261
         if (s != NULL)
2✔
2262
            vlog_add_stmt(v, s);
×
2263

2264
         vlog_set_loc(v, CURRENT_LOC);
2✔
2265
         return v;
2✔
2266
      }
2267

2268
   case tREPEAT:
2✔
2269
      {
2270
         vlog_node_t v = vlog_new(V_REPEAT);
2✔
2271

2272
         consume(tLPAREN);
2✔
2273
         vlog_set_value(v, p_expression());
2✔
2274
         consume(tRPAREN);
2✔
2275

2276
         vlog_node_t s = p_statement_or_null();
2✔
2277
         if (s != NULL)
2✔
2278
            vlog_add_stmt(v, s);
2✔
2279

2280
         vlog_set_loc(v, CURRENT_LOC);
2✔
2281
         return v;
2✔
2282
      }
2283

2284
   case tDO:
2✔
2285
      {
2286
         vlog_node_t v = vlog_new(V_DO_WHILE);
2✔
2287

2288
         vlog_node_t s = p_statement_or_null();
2✔
2289
         if (s != NULL)
2✔
2290
            vlog_add_stmt(v, s);
2✔
2291

2292
         consume(tWHILE);
2✔
2293

2294
         consume(tLPAREN);
2✔
2295
         vlog_set_value(v, p_expression());
2✔
2296
         consume(tRPAREN);
2✔
2297
         consume(tSEMI);
2✔
2298

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

2303
   case tFOR:
9✔
2304
      {
2305
         vlog_node_t v = vlog_new(V_FOR_LOOP);
9✔
2306

2307
         vlog_symtab_push(symtab, v);
9✔
2308

2309
         consume(tLPAREN);
9✔
2310

2311
         if (not_at_token(tSEMI))
9✔
2312
            vlog_set_left(v, p_for_initialization());
8✔
2313
         else
2314
            vlog_set_left(v, vlog_new(V_FOR_INIT));
1✔
2315

2316
         consume(tSEMI);
9✔
2317

2318
         if (not_at_token(tSEMI))
9✔
2319
            vlog_set_value(v, p_expression());
7✔
2320

2321
         consume(tSEMI);
9✔
2322

2323
         if (not_at_token(tRPAREN))
9✔
2324
            vlog_set_right(v, p_for_step());
8✔
2325
         else
2326
            vlog_set_right(v, vlog_new(V_FOR_STEP));
1✔
2327

2328
         consume(tRPAREN);
9✔
2329

2330
         vlog_node_t s = p_statement_or_null();
9✔
2331
         if (s != NULL)
9✔
2332
            vlog_add_stmt(v, s);
6✔
2333

2334
         vlog_symtab_pop(symtab);
9✔
2335

2336
         vlog_set_loc(v, CURRENT_LOC);
9✔
2337
         return v;
9✔
2338
      }
2339

2340
   default:
×
2341
      should_not_reach_here();
2342
   }
2343
}
2344

2345
static vlog_node_t p_wait_statement(void)
1✔
2346
{
2347
   // wait ( expression ) statement_or_null
2348
   //   | wait fork ;
2349
   //   | wait_order ( hierarchical_identifier { , hierarchical_identifier } )
2350
   //       action_block
2351

2352
   BEGIN("wait statement");
1✔
2353

2354
   consume(tWAIT);
1✔
2355

2356
   vlog_node_t v = vlog_new(V_WAIT);
1✔
2357

2358
   consume(tLPAREN);
1✔
2359

2360
   vlog_set_value(v, p_expression());
1✔
2361

2362
   consume(tRPAREN);
1✔
2363

2364
   vlog_node_t s = p_statement_or_null();
1✔
2365
   if (s != NULL)
1✔
2366
      vlog_add_stmt(v, s);
1✔
2367

2368
   vlog_set_loc(v, CURRENT_LOC);
1✔
2369
   return v;
1✔
2370
}
2371

2372
static vlog_node_t p_case_item(void)
42✔
2373
{
2374
   // case_item_expression { , case_item_expression } : statement_or_null
2375
   //   | default [ : ] statement_or_null
2376

2377
   BEGIN("case item");
42✔
2378

2379
   vlog_node_t v = vlog_new(V_CASE_ITEM);
42✔
2380

2381
   if (optional(tDEFAULT))
42✔
2382
      optional(tCOLON);
6✔
2383
   else {
2384
      do {
39✔
2385
         vlog_add_param(v, p_expression());
39✔
2386
      } while (optional(tCOMMA));
39✔
2387

2388
      consume(tCOLON);
36✔
2389
   }
2390

2391
   vlog_set_loc(v, CURRENT_LOC);
42✔
2392

2393
   vlog_node_t s = p_statement_or_null();
42✔
2394
   if (s != NULL)
42✔
2395
      vlog_add_stmt(v, s);
41✔
2396

2397
   return v;
42✔
2398
}
2399

2400
static vlog_node_t p_case_statement(void)
9✔
2401
{
2402
   // [ unique_priority ] case_keyword ( case_expression )
2403
   //        case_item { case_item } endcase
2404
   //   | [ unique_priority ] case_keyword ( case_expression ) matches
2405
   //        case_pattern_item { case_pattern_item } endcase
2406
   //   | [ unique_priority ] case ( case_expression ) inside case_inside_item
2407
   //        { case_inside_item } endcase
2408

2409
   BEGIN("case statement");
9✔
2410

2411
   vlog_case_kind_t kind = V_CASE_NORMAL;
9✔
2412
   switch (one_of(tCASE, tCASEX, tCASEZ)) {
9✔
2413
   case tCASEX: kind = V_CASE_X; break;
1✔
2414
   case tCASEZ: kind = V_CASE_Z; break;
×
2415
   }
2416

2417
   vlog_node_t v = vlog_new(V_CASE);
9✔
2418
   vlog_set_subkind(v, kind);
9✔
2419

2420
   consume(tLPAREN);
9✔
2421

2422
   vlog_set_value(v, p_expression());
9✔
2423

2424
   consume(tRPAREN);
9✔
2425

2426
   do {
42✔
2427
      vlog_add_stmt(v, p_case_item());
42✔
2428
   } while (not_at_token(tENDCASE));
42✔
2429

2430
   consume(tENDCASE);
9✔
2431

2432
   vlog_set_loc(v, CURRENT_LOC);
9✔
2433
   return v;
9✔
2434
}
2435

2436
static vlog_node_t p_event_trigger(void)
1✔
2437
{
2438
   // -> hierarchical_event_identifier ;
2439
   //   | ->> [ delay_or_event_control ] hierarchical_event_identifier ;
2440

2441
   BEGIN("event trigger");
1✔
2442

2443
   consume(tIFIMPL);
1✔
2444

2445
   vlog_node_t v = vlog_new(V_EVENT_TRIGGER);
1✔
2446
   vlog_set_ident(v, p_identifier());
1✔
2447

2448
   consume(tSEMI);
1✔
2449

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

2454
static vlog_node_t p_statement_item(void)
2,620✔
2455
{
2456
   // blocking_assignment ; | nonblocking_assignment ;
2457
   //   | procedural_continuous_assignment ; | case_statement
2458
   //   | conditional_statement | inc_or_dec_expression ;
2459
   //   | subroutine_call_statement | disable_statement
2460
   //   | event_trigger | loop_statement | jump_statement
2461
   //   | par_block | procedural_timing_control_statement
2462
   //   | seq_block | wait_statement | procedural_assertion_statement
2463
   //   | clocking_drive ; | randsequence_statement | randcase_statement
2464
   //   | expect_property_statement
2465

2466
   BEGIN("statement item");
5,240✔
2467

2468
   switch (peek()) {
2,620✔
2469
   case tID:
614✔
2470
      if (peek_nth(2) == tLPAREN)
614✔
2471
         return p_subroutine_call_statement();
3✔
2472
      else {
2473
         vlog_node_t lhs = p_variable_lvalue(), v = NULL;
611✔
2474

2475
         if (peek() == tLE)
611✔
2476
            v = p_nonblocking_assignment(lhs);
127✔
2477
         else
2478
            v = p_blocking_assignment(lhs);
484✔
2479

2480
         consume(tSEMI);
611✔
2481
         return v;
611✔
2482
      }
2483
   case tAT:
402✔
2484
   case tHASH:
2485
      return p_procedural_timing_control_statement();
402✔
2486
   case tBEGIN:
433✔
2487
      return p_seq_block();
433✔
2488
   case tFORK:
5✔
2489
      return p_par_block();
5✔
2490
   case tSYSTASK:
848✔
2491
   case tVOID:
2492
      return p_subroutine_call_statement();
848✔
2493
   case tIF:
285✔
2494
      return p_conditional_statement();
285✔
2495
   case tFOREVER:
20✔
2496
   case tWHILE:
2497
   case tREPEAT:
2498
   case tDO:
2499
   case tFOR:
2500
      return p_loop_statement();
20✔
2501
   case tWAIT:
1✔
2502
      return p_wait_statement();
1✔
2503
   case tCASE:
9✔
2504
   case tCASEX:
2505
   case tCASEZ:
2506
      return p_case_statement();
9✔
2507
   case tIFIMPL:
1✔
2508
      return p_event_trigger();
1✔
2509
   default:
2✔
2510
      one_of(tID, tAT, tHASH, tBEGIN, tFORK, tSYSTASK, tVOID, tIF, tFOREVER,
2✔
2511
             tWHILE, tREPEAT, tDO, tFOR, tWAIT, tCASE, tCASEX, tCASEZ, tIFIMPL);
2512
      drop_tokens_until(tSEMI);
2✔
2513
      return vlog_new(V_BLOCK);  // Dummy statement
2✔
2514
   }
2515
}
2516

2517
static vlog_node_t p_statement(void)
2,620✔
2518
{
2519
   // [ block_identifier : ] { attribute_instance } statement_item
2520

2521
   BEGIN("statement");
5,240✔
2522

2523
   if (peek() == tID && peek_nth(2) == tCOLON) {
2,620✔
2524
      (void)p_identifier();
2✔
2525
      consume(tCOLON);
2✔
2526
   }
2527

2528
   optional_attributes();
2,620✔
2529

2530
   return p_statement_item();
2,620✔
2531
}
2532

2533
static vlog_node_t p_statement_or_null(void)
2,636✔
2534
{
2535
   // statement | { attribute_instance } ;
2536

2537
   BEGIN("statement or null");
5,272✔
2538

2539
   if (optional(tSEMI))
2,636✔
2540
      return NULL;
2541
   else
2542
      return p_statement();
2,496✔
2543
}
2544

2545
static vlog_node_t p_always_construct(void)
124✔
2546
{
2547
   // always_keyword statement
2548

2549
   BEGIN("always construct");
124✔
2550

2551
   vlog_node_t v = vlog_new(V_ALWAYS);
124✔
2552

2553
   switch (one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH)) {
124✔
2554
   case tALWAYSCOMB:  vlog_set_subkind(v, V_ALWAYS_COMB);  break;
1✔
2555
   case tALWAYSFF:    vlog_set_subkind(v, V_ALWAYS_FF);    break;
1✔
2556
   case tALWAYSLATCH: vlog_set_subkind(v, V_ALWAYS_LATCH); break;
1✔
2557
   default:           vlog_set_subkind(v, V_ALWAYS_PLAIN); break;
121✔
2558
   }
2559

2560
   vlog_set_ident(v, ident_uniq("__always#line%d", yylloc.first_line));
124✔
2561
   vlog_add_stmt(v, p_statement());
124✔
2562

2563
   vlog_set_loc(v, CURRENT_LOC);
124✔
2564
   return v;
124✔
2565
}
2566

2567
static vlog_node_t p_initial_construct(void)
171✔
2568
{
2569
   // initial statement_or_null
2570

2571
   BEGIN("initial construct");
171✔
2572

2573
   consume(tINITIAL);
171✔
2574

2575
   vlog_node_t v = vlog_new(V_INITIAL);
171✔
2576
   vlog_set_ident(v, ident_uniq("__initial#line%d", yylloc.first_line));
171✔
2577

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

2582
   vlog_set_loc(v, CURRENT_LOC);
171✔
2583
   return v;
171✔
2584
}
2585

2586
static vlog_node_t p_net_assignment(void)
114✔
2587
{
2588
   // net_lvalue = expression
2589

2590
   BEGIN("net assignment");
114✔
2591

2592
   vlog_symtab_set_implicit(symtab, implicit_kind);
114✔
2593

2594
   vlog_node_t v = vlog_new(V_ASSIGN);
114✔
2595
   vlog_set_target(v, p_net_lvalue());
114✔
2596
   vlog_set_ident(v, ident_uniq("__assign#line%d", state.last_loc.first_line));
114✔
2597

2598
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
114✔
2599

2600
   consume(tEQ);
114✔
2601

2602
   vlog_set_value(v, p_expression());
114✔
2603

2604
   vlog_set_loc(v, CURRENT_LOC);
114✔
2605
   return v;
114✔
2606
}
2607

2608
static void p_list_of_net_assignments(vlog_node_t mod)
114✔
2609
{
2610
   // net_assignment { , net_assignment }
2611

2612
   BEGIN("list of net assignments");
228✔
2613

2614
   do {
114✔
2615
      vlog_add_stmt(mod, p_net_assignment());
114✔
2616
   } while (optional(tCOMMA));
114✔
2617
}
114✔
2618

2619
static void p_continuous_assign(vlog_node_t mod)
114✔
2620
{
2621
   // assign [ drive_strength ] [ delay3 ] list_of_net_assignments ;
2622
   //   | assign [ delay_control ] list_of_variable_assignments ;
2623

2624
   BEGIN("continuous assignment");
228✔
2625

2626
   consume(tASSIGN);
114✔
2627

2628
   if (peek() == tLPAREN) {
114✔
2629
      p_drive_strength();
3✔
2630
      if (peek() == tHASH)
3✔
2631
         p_delay3();
2✔
2632
   } else {
2633
      if (peek() == tHASH)
111✔
NEW
2634
         p_delay_control();
×
2635
   }
2636

2637
   p_list_of_net_assignments(mod);
114✔
2638

2639
   consume(tSEMI);
114✔
2640
}
114✔
2641

2642
static vlog_net_kind_t p_net_type(void)
137✔
2643
{
2644
   // supply0 | supply1 | tri | triand | trior | trireg | tri0
2645
   //   | tri1 | uwire | wire | wand | wor
2646

2647
   BEGIN("net type");
274✔
2648

2649
   switch (one_of(tWIRE, tUWIRE, tSUPPLY0, tSUPPLY1, tTRI, tTRIAND,
137✔
2650
                  tTRIOR, tTRIREG, tTRI0, tTRI1, tWAND, tWOR)) {
2651
   case tSUPPLY0: return V_NET_SUPPLY0;
2652
   case tSUPPLY1: return V_NET_SUPPLY1;
4✔
2653
   case tTRI:     return V_NET_TRI;
1✔
2654
   case tTRIAND:  return V_NET_TRIAND;
2✔
2655
   case tTRIOR:   return V_NET_TRIOR;
2✔
2656
   case tTRIREG:  return V_NET_TRIREG;
1✔
2657
   case tTRI0:    return V_NET_TRI0;
4✔
2658
   case tTRI1:    return V_NET_TRI1;
2✔
2659
   case tUWIRE:   return V_NET_UWIRE;
1✔
2660
   case tWAND:    return V_NET_WAND;
1✔
2661
   case tWOR:     return V_NET_WOR;
1✔
2662
   case tWIRE:
110✔
2663
   default:       return V_NET_WIRE;
110✔
2664
   }
2665
}
2666

2667
static vlog_node_t p_net_decl_assignment(vlog_net_kind_t kind,
171✔
2668
                                         vlog_node_t datatype)
2669
{
2670
   // net_identifier { unpacked_dimension } [ = expression ]
2671

2672
   BEGIN("net declaration assignment");
171✔
2673

2674
   vlog_node_t v = vlog_new(V_NET_DECL);
171✔
2675
   vlog_set_subkind(v, kind);
171✔
2676
   vlog_set_type(v, datatype);
171✔
2677
   vlog_set_ident(v, p_identifier());
171✔
2678

2679
   while (peek() == tLSQUARE)
172✔
2680
      vlog_add_range(v, p_unpacked_dimension());
1✔
2681

2682
   if (optional(tEQ))
171✔
2683
      vlog_set_value(v, p_expression());
13✔
2684

2685
   vlog_set_loc(v, CURRENT_LOC);
171✔
2686
   vlog_symtab_put(symtab, v);
171✔
2687
   return v;
171✔
2688
}
2689

2690
static void p_list_of_net_decl_assignments(vlog_node_t mod,
136✔
2691
                                           vlog_net_kind_t kind,
2692
                                           vlog_node_t datatype)
2693
{
2694
   // net_decl_assignment { , net_decl_assignment }
2695

2696
   BEGIN("list of net declaration assignments");
272✔
2697

2698
   do {
171✔
2699
      vlog_node_t v = p_net_decl_assignment(kind, datatype);
171✔
2700
      vlog_add_decl(mod, v);
171✔
2701
   } while (optional(tCOMMA));
171✔
2702
}
136✔
2703

2704
static vlog_node_t p_drive_strength(void)
5✔
2705
{
2706
   //( strength0 , strength1 ) | ( strength1 , strength0 )
2707
   //| ( strength0 , highz1 )  | ( strength1 , highz0 )
2708
   //| ( highz0 , strength1 )  | ( highz1 , strength0 )
2709

2710
   BEGIN("drive strength");
5✔
2711

2712
   consume(tLPAREN);
5✔
2713

2714
   vlog_strength_t s0, s1;
5✔
2715
   switch (peek()) {
5✔
2716
   case tSUPPLY0:
3✔
2717
   case tSTRONG0:
2718
   case tPULL0:
2719
   case tWEAK0:
2720
      {
2721
         s0 = p_strength0();
3✔
2722
         consume(tCOMMA);
3✔
2723
         if (optional(tHIGHZ1))
3✔
2724
            s1 = V_STRENGTH_HIGHZ;
2725
         else
2726
            s1 = p_strength1();
2✔
2727
      }
2728
      break;
2729
   case tHIGHZ0:
1✔
2730
      {
2731
         s0 = V_STRENGTH_HIGHZ;
1✔
2732
         consume(tHIGHZ0);
1✔
2733
         consume(tCOMMA);
1✔
2734
         s1 = p_strength1();
1✔
2735
      }
2736
      break;
1✔
NEW
2737
   case tSUPPLY1:
×
2738
   case tSTRONG1:
2739
   case tPULL1:
2740
   case tWEAK1:
2741
      {
NEW
2742
         s1 = p_strength1();
×
NEW
2743
         consume(tCOMMA);
×
NEW
2744
         if (optional(tHIGHZ0))
×
2745
            s0 = V_STRENGTH_HIGHZ;
2746
         else
NEW
2747
            s0 = p_strength0();
×
2748
      }
2749
      break;
2750
   case tHIGHZ1:
1✔
2751
      {
2752
         s1 = V_STRENGTH_HIGHZ;
1✔
2753
         consume(tHIGHZ1);
1✔
2754
         consume(tCOMMA);
1✔
2755
         s0 = p_strength0();
1✔
2756
      }
2757
      break;
1✔
NEW
2758
   default:
×
2759
      should_not_reach_here();
2760
   }
2761

2762
   consume(tRPAREN);
5✔
2763

2764
   vlog_node_t v = vlog_new(V_STRENGTH);
5✔
2765
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
5✔
2766
   vlog_set_loc(v, CURRENT_LOC);
5✔
2767

2768
   return v;
5✔
2769
}
2770

2771
static vlog_strength_t p_charge_strength(void)
2✔
2772
{
2773
   // ( small ) | ( medium ) | ( large )
2774

2775
   BEGIN("drive charge");
2✔
2776

2777
   consume(tLPAREN);
2✔
2778

2779
   vlog_strength_t s;
2✔
2780
   switch (one_of(tSMALL, tMEDIUM, tLARGE)) {
2✔
2781
   default:
2782
   case tSMALL:  s = V_STRENGTH_SMALL;
2783
   case tMEDIUM: s = V_STRENGTH_MEDIUM;
2✔
2784
   case tLARGE:  s = V_STRENGTH_LARGE;
2✔
2785
   }
2786

2787
   consume(tRPAREN);
2✔
2788

2789
   return s;
2✔
2790
}
2791

2792
static void p_net_declaration(vlog_node_t mod)
137✔
2793
{
2794
   // net_type [ drive_strength | charge_strength ] [ vectored | scalared ]
2795
   //     data_type_or_implicit [ delay3 ] list_of_net_decl_assignments ;
2796
   //  | net_type_identifier [ delay_control ] list_of_net_decl_assignments ;
2797
   //  | interconnect implicit_data_type [ # delay_value ] net_identifier
2798
   //     { unpacked_dimension } [ , net_identifier { unpacked_dimension } ] ;
2799

2800
   BEGIN("net declaration");
274✔
2801

2802
   ident_t id;
137✔
2803
   vlog_node_t dt;
137✔
2804
   vlog_net_kind_t kind = V_NET_WIRE;
137✔
2805

2806
   switch (peek()) {
137✔
2807
   case tINTERCONNECT:
1✔
2808
      {
2809
         consume(tINTERCONNECT);
1✔
2810

2811
         dt = p_implicit_data_type();
1✔
2812

2813
         if (optional(tHASH))
1✔
2814
            p_delay_value();
1✔
2815

2816
         do {
1✔
2817
            id = p_identifier();
1✔
2818
            if (peek() == tLSQUARE)
1✔
2819
               p_unpacked_dimension();
1✔
2820
         } while (optional(tCOMMA));
1✔
2821
      }
2822
      break;
2823

NEW
2824
   case tID:
×
2825
      {
NEW
2826
         id = p_identifier();
×
NEW
2827
         dt = vlog_symtab_query(symtab, id);
×
NEW
2828
         if (dt == NULL)
×
2829
            should_not_reach_here();
2830
         // TODO check that the identifier is actually
2831
         // a user declared nettype
2832

NEW
2833
         if (peek() == tHASH)
×
NEW
2834
            p_delay_control();
×
2835

NEW
2836
         p_list_of_net_decl_assignments(mod, kind, dt);
×
2837
      }
NEW
2838
      break;
×
2839

2840
   default:
136✔
2841
      {
2842
         kind = p_net_type();
136✔
2843

2844
         if (peek() == tLPAREN) {
136✔
2845
            switch (peek_nth(2)) {
4✔
2846
            case tHIGHZ0:
2✔
2847
            case tHIGHZ1:
2848
            case tSUPPLY0:
2849
            case tSUPPLY1:
2850
            case tSTRONG0:
2851
            case tSTRONG1:
2852
            case tPULL0:
2853
            case tPULL1:
2854
            case tWEAK0:
2855
            case tWEAK1:
2856
               p_drive_strength();
2✔
2857
               break;
2✔
2858
            case tSMALL:
2✔
2859
            case tMEDIUM:
2860
            case tLARGE:
2861
               if (kind != V_NET_TRIREG)
2✔
2862
                  parse_error(&state.last_loc, "charge strength only allowed with the trireg keyword");
1✔
2863
               p_charge_strength();
2✔
2864
               break;
2✔
NEW
2865
            default:
×
NEW
2866
               one_of(tHIGHZ0, tHIGHZ1, tSUPPLY0, tSUPPLY1, tSTRONG0, tSTRONG1,
×
2867
                     tPULL0, tPULL1, tWEAK0, tWEAK1, tSMALL, tMEDIUM, tLARGE);
NEW
2868
               drop_tokens_until(tSEMI);
×
NEW
2869
               return;
×
2870
            }
2871
         }
2872

2873
         bool need_packed = false;
136✔
2874
         if (optional(tVECTORED) || optional(tSCALARED))
136✔
2875
            need_packed = true;
2876

2877
         dt = p_data_type_or_implicit();
136✔
2878

2879
         if (need_packed) {
136✔
2880
            bool has_packed = false;
2✔
2881
            unsigned ranges = vlog_ranges(dt);
2✔
2882
            for (unsigned i = 0; i < ranges; i++) {
3✔
2883
               vlog_node_t r = vlog_range(dt, i);
1✔
2884
               if (vlog_subkind(r) == V_DIM_PACKED)
1✔
2885
                  has_packed |= true;
1✔
2886
            }
2887
            if (!has_packed)
2✔
2888
               parse_error(&state.last_loc, "vectored and scalared keywords are only allowed with at least a packed dimension");
1✔
2889
         }
2890

2891
         if (peek() == tHASH)
136✔
2892
            p_delay3();
5✔
2893

2894
         p_list_of_net_decl_assignments(mod, kind, dt);
136✔
2895
      }
2896
   }
2897

2898
   consume(tSEMI);
137✔
2899
}
2900

2901
static vlog_node_t p_variable_dimension(void)
14✔
2902
{
2903
   // unsized_dimension | unpacked_dimension | associative_dimension
2904
   //   | queue_dimension
2905

2906
   BEGIN("variable dimension");
28✔
2907

2908
   return p_unpacked_dimension();
14✔
2909
}
2910

2911
static vlog_node_t p_variable_decl_assignment(vlog_node_t datatype)
330✔
2912
{
2913
   // variable_identifier { variable_dimension } [ = expression ]
2914
   //   | dynamic_array_variable_identifier unsized_dimension
2915
   //       { variable_dimension } [ = dynamic_array_new ]
2916
   //   | class_variable_identifier [ = class_new ]
2917

2918
   BEGIN("variable declaration assignment");
330✔
2919

2920
   vlog_node_t v = vlog_new(V_VAR_DECL);
330✔
2921
   vlog_set_ident(v, p_identifier());
330✔
2922
   vlog_set_type(v, datatype);
330✔
2923

2924
   while (peek() == tLSQUARE)
344✔
2925
      vlog_add_range(v, p_variable_dimension());
14✔
2926

2927
   if (optional(tEQ))
330✔
2928
      vlog_set_value(v, p_expression());
24✔
2929

2930
   vlog_set_loc(v, CURRENT_LOC);
330✔
2931
   vlog_symtab_put(symtab, v);
330✔
2932
   return v;
330✔
2933
}
2934

2935
static void p_list_of_variable_decl_assignments(vlog_node_t parent,
268✔
2936
                                                vlog_node_t datatype)
2937
{
2938
   // variable_decl_assignment { , variable_decl_assignment }
2939

2940
   BEGIN("list of variable declaration assignments");
536✔
2941

2942
   do {
330✔
2943
      vlog_add_decl(parent, p_variable_decl_assignment(datatype));
330✔
2944
   } while (optional(tCOMMA));
330✔
2945
}
268✔
2946

2947
static vlog_node_t p_type_declaration(void)
3✔
2948
{
2949
   // typedef data_type type_identifier { variable_dimension } ;
2950
   //   | typedef interface_instance_identifier constant_bit_select .
2951
   //       type_identifier type_identifier ;
2952
   //   | typedef [ enum | struct | union | class | interface class ]
2953
   //       type_identifier ;
2954

2955
   BEGIN("type declaration");
3✔
2956

2957
   consume(tTYPEDEF);
3✔
2958

2959
   vlog_node_t v = vlog_new(V_TYPE_DECL);
3✔
2960
   vlog_set_type(v, p_data_type());
3✔
2961
   vlog_set_ident(v, p_identifier());
3✔
2962

2963
   consume(tSEMI);
3✔
2964

2965
   vlog_set_loc(v, CURRENT_LOC);
3✔
2966
   vlog_symtab_put(symtab, v);
3✔
2967
   return v;
3✔
2968
}
2969

2970
static void p_data_declaration(vlog_node_t mod)
262✔
2971
{
2972
   // [ const ] [ var ] [ lifetime ] data_type_or_implicit
2973
   //     list_of_variable_decl_assignments ;
2974
   //  | type_declaration | package_import_declaration | net_type_declaration
2975

2976
   BEGIN("data declaration");
524✔
2977

2978
   switch (peek()) {
262✔
2979
   case tTYPEDEF:
3✔
2980
      vlog_add_decl(mod, p_type_declaration());
3✔
2981
      break;
3✔
2982

2983
   default:
259✔
2984
      {
2985
         vlog_node_t dt = p_data_type_or_implicit();
259✔
2986
         p_list_of_variable_decl_assignments(mod, dt);
259✔
2987

2988
         consume(tSEMI);
259✔
2989
      }
2990
   }
2991
}
262✔
2992

2993
static v_port_kind_t p_port_direction(void)
11✔
2994
{
2995
   // input | output | inout | ref
2996

2997
   BEGIN("port direction");
22✔
2998

2999
   switch (one_of(tINPUT, tOUTPUT, tINOUT)) {
11✔
3000
   case tINPUT:  return V_PORT_INPUT;
3001
   case tOUTPUT: return V_PORT_OUTPUT;
2✔
3002
   case tINOUT:  return V_PORT_INOUT;
1✔
3003
   default:      return V_PORT_INPUT;
3004
   }
3005
}
3006

3007
static v_port_kind_t p_tf_port_direction(void)
11✔
3008
{
3009
   // port_direction | const ref
3010

3011
   BEGIN("task or function port direction");
22✔
3012

3013
   return p_port_direction();
11✔
3014
}
3015

3016
static vlog_node_t p_tf_port_item(void)
10✔
3017
{
3018
   // { attribute_instance } [ tf_port_direction ] [ var ]
3019
   //    data_type_or_implicit [ port_identifier { variable_dimension }
3020
   //    [ = expression ] ]
3021

3022
   BEGIN("task or function port item");
10✔
3023

3024
   vlog_node_t v = vlog_new(V_PORT_DECL);
10✔
3025

3026
   skip_over_attributes();
10✔
3027

3028
   if (scan(tINPUT, tOUTPUT, tINOUT))
10✔
3029
      vlog_set_subkind(v, p_tf_port_direction());
9✔
3030
   else
3031
      vlog_set_subkind(v, V_PORT_INPUT);
1✔
3032

3033
   vlog_set_type(v, p_data_type_or_implicit());
10✔
3034

3035
   if (peek() == tID) {
10✔
3036
      vlog_set_ident(v, p_identifier());
9✔
3037

3038
      if (optional(tEQ))
9✔
3039
         vlog_set_value(v, p_expression());
×
3040
   }
3041

3042
   vlog_set_loc(v, CURRENT_LOC);
10✔
3043
   return v;
10✔
3044
}
3045

3046
static void p_tf_port_list(vlog_node_t tf)
5✔
3047
{
3048
   // tf_port_item { , tf_port_item }
3049

3050
   BEGIN("task or function port list");
10✔
3051

3052
   do {
10✔
3053
      vlog_node_t v = p_tf_port_item();
10✔
3054
      vlog_add_port(tf, v);
10✔
3055

3056
      if (vlog_has_ident(v))  // Ignore unnamed ports
10✔
3057
         vlog_symtab_put(symtab, v);
9✔
3058
   } while (optional(tCOMMA));
10✔
3059
}
5✔
3060

3061
static void p_list_of_tf_variable_identifiers(vlog_node_t tf,
2✔
3062
                                              v_port_kind_t kind,
3063
                                              vlog_node_t dt)
3064
{
3065
   // port_identifier { variable_dimension } [ = expression ]
3066
   //    { , port_identifier { variable_dimension } [ = expression ] }
3067

3068
   BEGIN("list of task or function variable identifiers");
4✔
3069

3070
   do {
3✔
3071
      vlog_node_t v = vlog_new(V_PORT_DECL);
3✔
3072
      vlog_set_subkind(v, kind);
3✔
3073
      vlog_set_type(v, dt);
3✔
3074
      vlog_set_ident(v, p_identifier());
3✔
3075
      vlog_set_loc(v, &state.last_loc);
3✔
3076

3077
      if (optional(tEQ))
3✔
3078
         vlog_set_value(v, p_expression());
1✔
3079

3080
      vlog_add_port(tf, v);
3✔
3081
      vlog_symtab_put(symtab, v);
3✔
3082
   } while (optional(tCOMMA));
3✔
3083
}
2✔
3084

3085
static void p_tf_port_declaration(vlog_node_t tf)
2✔
3086
{
3087
   // { attribute_instance } tf_port_direction [ var ] data_type_or_implicit
3088
   //    list_of_tf_variable_identifiers ;
3089

3090
   BEGIN("task or function port declaration");
4✔
3091

3092
   v_port_kind_t kind = p_tf_port_direction();
2✔
3093

3094
   optional(tVAR);
2✔
3095

3096
   vlog_node_t dt = p_data_type_or_implicit();
2✔
3097

3098
   p_list_of_tf_variable_identifiers(tf, kind, dt);
2✔
3099

3100
   consume(tSEMI);
2✔
3101
}
2✔
3102

3103
static void p_tf_item_declaration(vlog_node_t tf)
5✔
3104
{
3105
   // block_item_declaration | tf_port_declaration
3106

3107
   BEGIN("task or function item declaration");
10✔
3108

3109
   switch (peek()) {
5✔
3110
   case tINPUT:
2✔
3111
   case tOUTPUT:
3112
   case tCONST:
3113
      p_tf_port_declaration(tf);
2✔
3114
      break;
2✔
3115
   default:
3✔
3116
      p_block_item_declaration(tf);
3✔
3117
      break;
3✔
3118
   }
3119
}
5✔
3120

3121
static void p_task_body_declaration(vlog_node_t task)
5✔
3122
{
3123
   // [ interface_identifier . | class_scope ] task_identifier ;
3124
   //    { tf_item_declaration } { statement_or_null }
3125
   //    endtask [ : task_identifier ]
3126
   // | [ interface_identifier . | class_scope ] task_identifier
3127
   //    ( [ tf_port_list ] ) ; { block_item_declaration }
3128
   //    { statement_or_null } endtask [ : task_identifier ]
3129

3130
   BEGIN("task body declaration");
10✔
3131

3132
   ident_t id = p_identifier();
5✔
3133
   vlog_set_ident(task, id);
5✔
3134
   vlog_set_loc(task, &state.last_loc);
5✔
3135

3136
   vlog_symtab_put(symtab, task);
5✔
3137

3138
   vlog_symtab_push(symtab, task);
5✔
3139

3140
   if (optional(tLPAREN)) {
5✔
3141
      if (peek() != tRPAREN)
2✔
3142
         p_tf_port_list(task);
2✔
3143
      consume(tRPAREN);
2✔
3144

3145
      consume(tSEMI);
2✔
3146

3147
      skip_over_attributes();
2✔
3148

3149
      while (scan(tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM, tSVINT, tINTEGER,
2✔
3150
                  tSVREAL, tSHORTREAL, tREALTIME, tBIT, tLOGIC)) {
3151
         p_block_item_declaration(task);
×
3152
         skip_over_attributes();
×
3153
      }
3154
   }
3155
   else {
3156
      consume(tSEMI);
3✔
3157

3158
      skip_over_attributes();
3✔
3159

3160
      while (scan(tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM, tSVINT, tINTEGER,
7✔
3161
                  tSVREAL, tSHORTREAL, tREALTIME, tBIT, tLOGIC, tINPUT,
3162
                  tOUTPUT)) {
3163
         p_tf_item_declaration(task);
4✔
3164
         skip_over_attributes();
4✔
3165
      }
3166
   }
3167

3168
   while (not_at_token(tENDTASK)) {
9✔
3169
      vlog_node_t s = p_statement_or_null();
4✔
3170
      if (s != NULL)
4✔
3171
         vlog_add_stmt(task, s);
4✔
3172
   }
3173

3174
   consume(tENDTASK);
5✔
3175

3176
   vlog_symtab_pop(symtab);
5✔
3177
}
5✔
3178

3179
static void p_lifetime(void)
1✔
3180
{
3181
   // static | automatic
3182

3183
   BEGIN("lifetime");
2✔
3184

3185
   one_of(tAUTOMATIC);
1✔
3186
}
1✔
3187

3188
static vlog_node_t p_task_declaration(void)
5✔
3189
{
3190
   // task [ dynamic_override_specifiers ] [ lifetime ] task_body_declaration
3191

3192
   BEGIN("task declaration");
5✔
3193

3194
   vlog_node_t v = vlog_new(V_TASK_DECL);
5✔
3195

3196
   consume(tTASK);
5✔
3197

3198
   if (scan(tAUTOMATIC))
5✔
3199
      p_lifetime();
×
3200

3201
   p_task_body_declaration(v);
5✔
3202

3203
   vlog_set_loc(v, CURRENT_LOC);
5✔
3204
   return v;
5✔
3205
}
3206

3207
static vlog_node_t p_function_data_type_or_implicit(void)
5✔
3208
{
3209
   // data_type_or_void | implicit_data_type
3210

3211
   BEGIN("function data type or implicit");
10✔
3212

3213
   if (scan(tREG, tSTRUCT, tUNION, tENUM, tSVINT, tINTEGER, tSVREAL,
5✔
3214
            tSHORTREAL, tREALTIME, tLOGIC, tBIT, tEVENT))
3215
      return p_data_type_or_void();
1✔
3216
   else
3217
      return p_implicit_data_type();
4✔
3218
}
3219

3220
static void p_function_body_declaration(vlog_node_t func)
5✔
3221
{
3222
   // function_data_type_or_implicit [ interface_identifier . | class_scope ]
3223
   //    function_identifier ; { tf_item_declaration }
3224
   //    { function_statement_or_null } endfunction [ : function_identifier ]
3225
   // | function_data_type_or_implicit [ interface_identifier . | class_scope ]
3226
   //    function_identifier ( [ tf_port_list ] ) ; { block_item_declaration }
3227
   //    { function_statement_or_null } endfunction [ : function_identifier ]
3228

3229
   BEGIN("function body declaration");
10✔
3230

3231
   vlog_set_type(func, p_function_data_type_or_implicit());
5✔
3232

3233
   ident_t id = p_identifier();
5✔
3234
   vlog_set_ident(func, id);
5✔
3235
   vlog_set_loc(func, &state.last_loc);
5✔
3236

3237
   vlog_symtab_put(symtab, func);
5✔
3238

3239
   vlog_symtab_push(symtab, func);
5✔
3240

3241
   if (optional(tLPAREN)) {
5✔
3242
      if (peek() != tRPAREN)
4✔
3243
         p_tf_port_list(func);
3✔
3244
      consume(tRPAREN);
4✔
3245

3246
      consume(tSEMI);
4✔
3247

3248
      skip_over_attributes();
4✔
3249

3250
      while (scan(tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM, tSVINT, tINTEGER,
4✔
3251
                  tSVREAL, tSHORTREAL, tREALTIME, tBIT, tLOGIC)) {
3252
         p_block_item_declaration(func);
×
3253
         skip_over_attributes();
×
3254
      }
3255
   }
3256
   else {
3257
      consume(tSEMI);
1✔
3258

3259
      skip_over_attributes();
1✔
3260

3261
      while (scan(tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM, tSVINT, tINTEGER,
2✔
3262
                  tSVREAL, tSHORTREAL, tREALTIME, tBIT, tLOGIC, tINPUT,
3263
                  tOUTPUT)) {
3264
         p_tf_item_declaration(func);
1✔
3265
         skip_over_attributes();
1✔
3266
      }
3267
   }
3268

3269
   while (not_at_token(tENDFUNCTION)) {
10✔
3270
      vlog_node_t s = p_statement_or_null();
5✔
3271
      if (s != NULL)
5✔
3272
         vlog_add_stmt(func, s);
5✔
3273
   }
3274

3275
   consume(tENDFUNCTION);
5✔
3276

3277
   vlog_symtab_pop(symtab);
5✔
3278
}
5✔
3279

3280
static vlog_node_t p_function_declaration(void)
5✔
3281
{
3282
   // function [ lifetime ] function_body_declaration
3283

3284
   BEGIN("function declaration");
5✔
3285

3286
   vlog_node_t v = vlog_new(V_FUNC_DECL);
5✔
3287

3288
   consume(tFUNCTION);
5✔
3289

3290
   if (scan(tAUTOMATIC))
5✔
3291
      p_lifetime();
1✔
3292

3293
   p_function_body_declaration(v);
5✔
3294

3295
   vlog_set_loc(v, CURRENT_LOC);
5✔
3296
   return v;
5✔
3297
}
3298

3299
static vlog_node_t p_constant_param_expression(void)
26✔
3300
{
3301
   // mintypmax_expression | data_type | $
3302

3303
   BEGIN("constant parameter expression");
52✔
3304

3305
   return p_mintypmax_expression();
26✔
3306
}
3307

3308
static vlog_node_t p_param_assignment(vlog_node_t datatype, vlog_kind_t kind)
38✔
3309
{
3310
   // parameter_identifier { unpacked_dimension }
3311
   //   [ = constant_param_expression ]
3312

3313
   BEGIN("parameter assignment");
38✔
3314

3315
   vlog_node_t v = vlog_new(kind);
38✔
3316
   vlog_set_ident(v, p_identifier());
38✔
3317
   vlog_set_type(v, datatype);
38✔
3318

3319
   if (optional(tEQ))
38✔
3320
      vlog_set_value(v, p_constant_param_expression());
26✔
3321

3322
   vlog_set_loc(v, CURRENT_LOC);
38✔
3323
   return v;
38✔
3324
}
3325

3326
static void p_list_of_param_assignments(vlog_node_t parent,
36✔
3327
                                        vlog_node_t datatype,
3328
                                        vlog_kind_t kind)
3329
{
3330
   // param_assignment { , param_assignment }
3331

3332
   BEGIN("list of parameter assignments");
72✔
3333

3334
   do {
38✔
3335
      vlog_node_t v = p_param_assignment(datatype, kind);
38✔
3336
      vlog_symtab_put(symtab, v);
38✔
3337
      vlog_add_decl(parent, v);
38✔
3338
   } while (peek_nth(2) == tID && optional(tCOMMA));
38✔
3339
}
36✔
3340

3341
static void p_parameter_declaration(vlog_node_t mod)
28✔
3342
{
3343
   // parameter data_type_or_implicit list_of_param_assignments
3344

3345
   BEGIN("parameter declaration");
56✔
3346

3347
   consume(tPARAMETER);
28✔
3348

3349
   vlog_node_t dt = p_data_type_or_implicit();
28✔
3350
   p_list_of_param_assignments(mod, dt, param_kind);
28✔
3351
}
28✔
3352

3353
static void p_local_parameter_declaration(vlog_node_t mod)
6✔
3354
{
3355
   // localparam data_type_or_implicit list_of_param_assignments
3356

3357
   BEGIN("local parameter declaration");
12✔
3358

3359
   consume(tLOCALPARAM);
6✔
3360

3361
   vlog_node_t dt = p_data_type_or_implicit();
6✔
3362
   p_list_of_param_assignments(mod, dt, V_LOCALPARAM);
6✔
3363
}
6✔
3364

3365
static void p_block_item_declaration(vlog_node_t parent)
7✔
3366
{
3367
   // { attribute_instance } data_declaration
3368
   //   | { attribute_instance } local_parameter_declaration ;
3369
   //   | { attribute_instance } parameter_declaration ;
3370
   //   | { attribute_instance } overload_declaration
3371
   //   | { attribute_instance } let_declaration
3372

3373
   BEGIN("block item declaration");
7✔
3374

3375
   optional_attributes();
7✔
3376

3377
   switch (peek()) {
7✔
3378
   case tREG:
7✔
3379
   case tSTRUCT:
3380
   case tUNION:
3381
   case tTYPEDEF:
3382
   case tENUM:
3383
   case tSVINT:
3384
   case tINTEGER:
3385
   case tSVREAL:
3386
   case tSHORTREAL:
3387
   case tREALTIME:
3388
   case tBIT:
3389
   case tLOGIC:
3390
      p_data_declaration(parent);
7✔
3391
      break;
7✔
3392
   default:
×
3393
      should_not_reach_here();
3394
   }
3395
}
7✔
3396

3397
static void p_package_or_generate_item_declaration(vlog_node_t mod)
433✔
3398
{
3399
   // net_declaration | data_declaration | task_declaration
3400
   //   | function_declaration | checker_declaration | dpi_import_export
3401
   //   | extern_constraint_declaration | class_declaration
3402
   //   | class_constructor_declaration | local_parameter_declaration ;
3403
   //   | parameter_declaration ; | covergroup_declaration
3404
   //   | overload_declaration | assertion_item_declaration | ;
3405

3406
   BEGIN("package or generate item declaration");
866✔
3407

3408
   switch (peek()) {
433✔
3409
   case tWIRE:
137✔
3410
   case tUWIRE:
3411
   case tSUPPLY0:
3412
   case tSUPPLY1:
3413
   case tTRI:
3414
   case tTRI0:
3415
   case tTRI1:
3416
   case tTRIAND:
3417
   case tTRIOR:
3418
   case tTRIREG:
3419
   case tWAND:
3420
   case tWOR:
3421
   case tINTERCONNECT:
3422
      p_net_declaration(mod);
137✔
3423
      break;
137✔
3424
   case tREG:
255✔
3425
   case tSTRUCT:
3426
   case tUNION:
3427
   case tTYPEDEF:
3428
   case tENUM:
3429
   case tSVINT:
3430
   case tINTEGER:
3431
   case tSVREAL:
3432
   case tSHORTREAL:
3433
   case tREALTIME:
3434
   case tTIME:
3435
   case tEVENT:
3436
   case tID:
3437
      p_data_declaration(mod);
255✔
3438
      break;
255✔
3439
   case tTASK:
5✔
3440
      vlog_add_decl(mod, p_task_declaration());
5✔
3441
      break;
5✔
3442
   case tFUNCTION:
5✔
3443
      vlog_add_decl(mod, p_function_declaration());
5✔
3444
      break;
5✔
3445
   case tLOCALPARAM:
5✔
3446
      p_local_parameter_declaration(mod);
5✔
3447
      consume(tSEMI);
5✔
3448
      break;
5✔
3449
   case tPARAMETER:
26✔
3450
      p_parameter_declaration(mod);
26✔
3451
      consume(tSEMI);
26✔
3452
      break;
26✔
3453
   default:
×
NEW
3454
      one_of(tWIRE, tUWIRE, tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND,
×
3455
             tTRIOR, tTRIREG, tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION,
3456
             tTYPEDEF, tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME,
3457
             tTIME, tEVENT, tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER);
3458
      drop_tokens_until(tSEMI);
×
3459
      break;
×
3460
   }
3461
}
433✔
3462

3463
static void p_list_of_genvar_identifiers(vlog_node_t mod)
1✔
3464
{
3465
   // genvar_identifier { , genvar_identifier }
3466

3467
   BEGIN("list of genvar identifiers");
2✔
3468

3469
   do {
1✔
3470
      vlog_node_t v = vlog_new(V_GENVAR_DECL);
1✔
3471
      vlog_set_ident(v, p_identifier());
1✔
3472
      vlog_set_loc(v, CURRENT_LOC);
1✔
3473

3474
      vlog_add_decl(mod, v);
1✔
3475

3476
      vlog_symtab_put(symtab, v);
1✔
3477
   } while (optional(tCOMMA));
1✔
3478
}
1✔
3479

3480
static void p_genvar_declaration(vlog_node_t mod)
1✔
3481
{
3482
   // genvar list_of_genvar_identifiers ;
3483

3484
   BEGIN("genvar declaration");
2✔
3485

3486
   consume(tGENVAR);
1✔
3487

3488
   p_list_of_genvar_identifiers(mod);
1✔
3489

3490
   consume(tSEMI);
1✔
3491
}
1✔
3492

3493
static void p_module_or_generate_item_declaration(vlog_node_t mod)
434✔
3494
{
3495
   // package_or_generate_item_declaration | genvar_declaration
3496
   //   | clocking_declaration | default clocking clocking_identifier ;
3497
   //   | default disable iff expression_or_dist ;
3498

3499
   BEGIN("module or generate item declaration");
868✔
3500

3501
   switch (peek()) {
434✔
3502
   case tGENVAR:
1✔
3503
      p_genvar_declaration(mod);
1✔
3504
      break;
1✔
3505
   default:
433✔
3506
      p_package_or_generate_item_declaration(mod);
433✔
3507
      break;
433✔
3508
   }
3509
}
434✔
3510

3511
static void p_generate_item(vlog_node_t parent)
18✔
3512
{
3513
   // module_or_generate_item | interface_or_generate_item
3514
   //   | checker_or_generate_item
3515

3516
   BEGIN("generate item");
36✔
3517

3518
   p_module_or_generate_item(parent);
18✔
3519
}
18✔
3520

3521
static void p_generate_block(vlog_node_t parent)
16✔
3522
{
3523
   // generate_item
3524
   //   | [ generate_block_identifier : ] begin [ : generate_block_identifier ]
3525
   //         { generate_item } end [ : generate_block_identifier ]
3526

3527
   BEGIN("generate item");
32✔
3528

3529
   if (scan(tID, tBEGIN)) {
16✔
3530
      vlog_node_t b = vlog_new(V_BLOCK);
15✔
3531

3532
      if (peek() == tID) {
15✔
3533
         vlog_set_ident(b, p_identifier());
1✔
3534
         consume(tCOLON);
1✔
3535
      }
3536

3537
      consume(tBEGIN);
15✔
3538

3539
      if (optional(tCOLON)) {
15✔
3540
         ident_t name = p_identifier();
1✔
3541
         if (vlog_has_ident(b))    // 1800-2023 section 9.3.5
1✔
3542
            parse_error(&state.last_loc, "cannot specify both a label and a "
1✔
3543
                        "name for the same block");
3544
         else
3545
            vlog_set_ident(b, name);
×
3546
      }
3547

3548
      vlog_symtab_push(symtab, b);
15✔
3549

3550
      while (not_at_token(tEND))
27✔
3551
         p_generate_item(b);
12✔
3552

3553
      vlog_symtab_pop(symtab);
15✔
3554

3555
      consume(tEND);
15✔
3556

3557
      if (optional(tCOLON)) {
15✔
3558
         ident_t name = p_identifier();
2✔
3559
         if (!vlog_has_ident(b))
2✔
3560
            parse_error(&state.last_loc, "block does not have a label");
1✔
3561
         else if (name != vlog_ident(b))
1✔
3562
            parse_error(&state.last_loc, "'%s' does not match label '%s'",
1✔
3563
                        istr(name), istr(vlog_ident(b)));
3564
      }
3565

3566
      vlog_set_loc(b, CURRENT_LOC);
15✔
3567
      vlog_add_stmt(parent, b);
15✔
3568
   }
3569
   else
3570
      p_generate_item(parent);
1✔
3571
}
16✔
3572

3573
static vlog_node_t p_if_generate_construct(void)
9✔
3574
{
3575
   // if ( constant_expression ) generate_block [ else generate_block ]
3576

3577
   BEGIN("if generate construct");
9✔
3578

3579
   vlog_node_t v = vlog_new(V_IF_GENERATE);
9✔
3580

3581
   consume(tIF);
9✔
3582
   consume(tLPAREN);
9✔
3583

3584
   vlog_node_t c0 = vlog_new(V_COND);
9✔
3585
   vlog_set_value(c0, p_constant_expression());
9✔
3586

3587
   consume(tRPAREN);
9✔
3588

3589
   vlog_set_loc(c0, CURRENT_LOC);
9✔
3590

3591
   p_generate_block(c0);
9✔
3592

3593
   vlog_add_cond(v, c0);
9✔
3594

3595
   if (optional(tELSE)) {
9✔
3596
      vlog_node_t c1 = vlog_new(V_COND);
6✔
3597
      vlog_set_loc(c1, &state.last_loc);
6✔
3598

3599
      p_generate_block(c1);
6✔
3600

3601
      vlog_add_cond(v, c1);
6✔
3602
   }
3603

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

3608
static vlog_node_t p_conditional_generate_construct(void)
9✔
3609
{
3610
   // if_generate_construct | case_generate_construct
3611

3612
   BEGIN("conditional generate construct");
18✔
3613

3614
   switch (peek()) {
9✔
3615
   case tIF:
9✔
3616
      return p_if_generate_construct();
18✔
3617
   default:
×
3618
      should_not_reach_here();
3619
   }
3620
}
3621

3622
static vlog_node_t p_genvar_initialization(void)
1✔
3623
{
3624
   // [ genvar ] genvar_identifier = constant_expression
3625

3626
   BEGIN("genvar initialization");
1✔
3627

3628
   vlog_node_t v = vlog_new(V_FOR_INIT);
1✔
3629

3630
   vlog_node_t ref = vlog_new(V_REF);
1✔
3631
   vlog_set_ident(ref, p_identifier());
1✔
3632
   vlog_set_loc(ref, &state.last_loc);
1✔
3633

3634
   vlog_symtab_lookup(symtab, ref);
1✔
3635

3636
   consume(tEQ);
1✔
3637

3638
   vlog_node_t a = vlog_new(V_BASSIGN);
1✔
3639
   vlog_set_target(a, ref);
1✔
3640
   vlog_set_value(a, p_constant_expression());
1✔
3641
   vlog_set_loc(a, CURRENT_LOC);
1✔
3642

3643
   vlog_add_stmt(v, a);
1✔
3644

3645
   vlog_set_loc(v, CURRENT_LOC);
1✔
3646
   return v;
1✔
3647
}
3648

3649
static vlog_node_t p_genvar_iteration(void)
1✔
3650
{
3651
   // genvar_identifier assignment_operator genvar_expression
3652
   //   | inc_or_dec_operator genvar_identifier
3653
   //   | genvar_identifier inc_or_dec_operator
3654

3655
   BEGIN("genvar iteration");
1✔
3656

3657
   vlog_node_t v = vlog_new(V_FOR_STEP);
1✔
3658

3659
   vlog_node_t ref = vlog_new(V_REF);
1✔
3660
   vlog_set_ident(ref, p_identifier());
1✔
3661
   vlog_set_loc(ref, &state.last_loc);
1✔
3662

3663
   vlog_node_t a = vlog_new(V_POSTFIX);
1✔
3664
   vlog_set_subkind(a, p_inc_or_dec_operator());
1✔
3665
   vlog_set_target(a, ref);
1✔
3666

3667
   vlog_set_loc(v, CURRENT_LOC);
1✔
3668
   return v;
1✔
3669
}
3670

3671
static vlog_node_t p_loop_generate_construct(void)
1✔
3672
{
3673
   // for ( genvar_initialization ; genvar_expression ; genvar_iteration )
3674
   //   generate_block
3675

3676
   BEGIN("loop generate construct");
1✔
3677

3678
   consume(tFOR);
1✔
3679
   consume(tLPAREN);
1✔
3680

3681
   vlog_node_t v = vlog_new(V_FOR_GENERATE);
1✔
3682

3683
   vlog_symtab_push(symtab, v);
1✔
3684

3685
   vlog_set_left(v, p_genvar_initialization());
1✔
3686

3687
   consume(tSEMI);
1✔
3688

3689
   vlog_set_value(v, p_constant_expression());
1✔
3690

3691
   consume(tSEMI);
1✔
3692

3693
   vlog_set_right(v, p_genvar_iteration());
1✔
3694

3695
   consume(tRPAREN);
1✔
3696

3697
   p_generate_block(v);
1✔
3698

3699
   vlog_symtab_pop(symtab);
1✔
3700

3701
   vlog_set_loc(v, CURRENT_LOC);
1✔
3702
   return v;
1✔
3703
}
3704

3705
static void p_module_common_item(vlog_node_t mod)
853✔
3706
{
3707
   // module_or_generate_item_declaration
3708
   //   | interface_instantiation | program_instantiation
3709
   //   | assertion_item | bind_directive | continuous_assign
3710
   //   | net_alias | initial_construct | final_construct
3711
   //   | always_construct | loop_generate_construct
3712
   //   | conditional_generate_construct | elaboration_system_task
3713

3714
   BEGIN("module common item");
1,706✔
3715

3716
   switch (peek()) {
853✔
3717
   case tALWAYS:
124✔
3718
   case tALWAYSCOMB:
3719
   case tALWAYSFF:
3720
   case tALWAYSLATCH:
3721
      vlog_add_stmt(mod, p_always_construct());
124✔
3722
      break;
124✔
3723
   case tINITIAL:
171✔
3724
      vlog_add_stmt(mod, p_initial_construct());
171✔
3725
      break;
171✔
3726
   case tWIRE:
434✔
3727
   case tUWIRE:
3728
   case tSUPPLY0:
3729
   case tSUPPLY1:
3730
   case tTRI:
3731
   case tTRI0:
3732
   case tTRI1:
3733
   case tTRIAND:
3734
   case tTRIOR:
3735
   case tTRIREG:
3736
   case tWAND:
3737
   case tWOR:
3738
   case tINTERCONNECT:
3739
   case tREG:
3740
   case tSTRUCT:
3741
   case tUNION:
3742
   case tTYPEDEF:
3743
   case tENUM:
3744
   case tSVINT:
3745
   case tINTEGER:
3746
   case tSVREAL:
3747
   case tSHORTREAL:
3748
   case tREALTIME:
3749
   case tTIME:
3750
   case tTASK:
3751
   case tFUNCTION:
3752
   case tLOCALPARAM:
3753
   case tPARAMETER:
3754
   case tEVENT:
3755
   case tID:
3756
   case tGENVAR:
3757
      p_module_or_generate_item_declaration(mod);
434✔
3758
      break;
434✔
3759
   case tASSIGN:
114✔
3760
      p_continuous_assign(mod);
114✔
3761
      break;
114✔
3762
   case tFOR:
1✔
3763
      vlog_add_stmt(mod, p_loop_generate_construct());
1✔
3764
      break;
1✔
3765
   case tIF:
9✔
3766
      vlog_add_stmt(mod, p_conditional_generate_construct());
9✔
3767
      break;
9✔
3768
   default:
×
3769
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
×
3770
             tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
3771
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM,
3772
             tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTIME, tTASK,
3773
             tFUNCTION, tPARAMETER, tLOCALPARAM, tEVENT, tID, tGENVAR, tASSIGN,
3774
             tFOR, tIF);
UNCOV
3775
      drop_tokens_until(tSEMI);
×
3776
   }
3777
}
853✔
3778

3779
static vlog_strength_t p_strength0(void)
8✔
3780
{
3781
   // supply0 | strong0 | pull0 | weak0
3782

3783
   BEGIN("strength0");
16✔
3784

3785
   switch (one_of(tSUPPLY0, tSTRONG0, tPULL0, tWEAK0)) {
8✔
3786
   default:
3787
   case tSUPPLY0: return V_STRENGTH_SUPPLY;
3788
   case tSTRONG0: return V_STRENGTH_STRONG;
3789
   case tPULL0:   return V_STRENGTH_PULL;
3790
   case tWEAK0:   return V_STRENGTH_WEAK;
3791
   }
3792
}
3793

3794
static vlog_strength_t p_strength1(void)
10✔
3795
{
3796
   // supply1 | strong1 | pull1 | weak1
3797

3798
   BEGIN("strength1");
20✔
3799

3800
   switch (one_of(tSUPPLY1, tSTRONG1, tPULL1, tWEAK1)) {
10✔
3801
   default:
3802
   case tSUPPLY1: return V_STRENGTH_SUPPLY;
3803
   case tSTRONG1: return V_STRENGTH_STRONG;
3804
   case tPULL1:   return V_STRENGTH_PULL;
3805
   case tWEAK1:   return V_STRENGTH_WEAK;
3806
   }
3807
}
3808

3809
static vlog_node_t p_pulldown_strength(void)
2✔
3810
{
3811
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength0 )
3812

3813
   BEGIN("pulldown strength");
2✔
3814

3815
   consume(tLPAREN);
2✔
3816

3817
   vlog_strength_t s0, s1;
2✔
3818
   switch (peek()) {
2✔
3819
   case tSUPPLY1:
×
3820
   case tSTRONG1:
3821
   case tPULL1:
3822
   case tWEAK1:
3823
      s1 = p_strength1();
×
3824
      consume(tCOMMA);
×
3825
      s0 = p_strength0();
×
3826
      break;
×
3827
   default:
2✔
3828
      s0 = s1 = p_strength0();
2✔
3829
      if (optional(tCOMMA))
2✔
3830
         s1 = p_strength1();
×
3831
      break;
3832
   }
3833

3834
   consume(tRPAREN);
2✔
3835

3836
   vlog_node_t v = vlog_new(V_STRENGTH);
2✔
3837
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
2✔
3838
   vlog_set_loc(v, CURRENT_LOC);
2✔
3839
   return v;
2✔
3840
}
3841

3842
static vlog_node_t p_pullup_strength(void)
7✔
3843
{
3844
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength1 )
3845

3846
   BEGIN("pullup strength");
7✔
3847

3848
   consume(tLPAREN);
7✔
3849

3850
   vlog_strength_t s0, s1;
7✔
3851
   switch (peek()) {
7✔
3852
   case tSUPPLY0:
1✔
3853
   case tSTRONG0:
3854
   case tPULL0:
3855
   case tWEAK0:
3856
      s0 = p_strength0();
1✔
3857
      consume(tCOMMA);
1✔
3858
      s1 = p_strength1();
1✔
3859
      break;
1✔
3860
   default:
6✔
3861
      s1 = s0 = p_strength1();
6✔
3862
      if (optional(tCOMMA))
6✔
3863
         s0 = p_strength0();
1✔
3864
      break;
3865
   }
3866

3867
   consume(tRPAREN);
7✔
3868

3869
   vlog_node_t v = vlog_new(V_STRENGTH);
7✔
3870
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
7✔
3871
   vlog_set_loc(v, CURRENT_LOC);
7✔
3872
   return v;
7✔
3873
}
3874

3875
static vlog_node_t p_pull_gate_instance(vlog_gate_kind_t kind, vlog_node_t st)
22✔
3876
{
3877
   // [ name_of_instance ] ( output_terminal )
3878

3879
   BEGIN("pull gate instance");
22✔
3880

3881
   vlog_node_t v = vlog_new(V_GATE_INST);
22✔
3882
   vlog_set_subkind(v, kind);
22✔
3883
   vlog_add_param(v, st);
22✔
3884

3885
   if (peek() == tID) {
22✔
3886
      vlog_set_ident(v, p_identifier());
7✔
3887
      vlog_set_loc(v, &state.last_loc);
7✔
3888
      vlog_symtab_put(symtab, v);
7✔
3889
   }
3890
   else
3891
      vlog_set_ident(v, ident_uniq("#gate"));
15✔
3892

3893
   consume(tLPAREN);
22✔
3894

3895
   vlog_symtab_set_implicit(symtab, implicit_kind);
22✔
3896

3897
   vlog_set_target(v, p_net_lvalue());
22✔
3898

3899
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
22✔
3900

3901
   consume(tRPAREN);
22✔
3902

3903
   vlog_set_loc(v, CURRENT_LOC);
22✔
3904
   return v;
22✔
3905
}
3906

3907
static vlog_node_t p_n_terminal_gate_instance(vlog_gate_kind_t kind)
23✔
3908
{
3909
   // [ name_of_instance ] ( output_terminal , input_terminal
3910
   //     { , input_terminal } )
3911

3912
   BEGIN("N-terminal gate instance");
23✔
3913

3914
   vlog_node_t v = vlog_new(V_GATE_INST);
23✔
3915
   vlog_set_subkind(v, kind);
23✔
3916

3917
   if (peek() == tID) {
23✔
3918
      vlog_set_ident(v, p_identifier());
2✔
3919
      vlog_set_loc(v, &state.last_loc);
2✔
3920
      vlog_symtab_put(symtab, v);
2✔
3921
   }
3922
   else
3923
      vlog_set_ident(v, ident_uniq("#gate"));
21✔
3924

3925
   consume(tLPAREN);
23✔
3926

3927
   vlog_symtab_set_implicit(symtab, implicit_kind);
23✔
3928

3929
   vlog_set_target(v, p_net_lvalue());
23✔
3930

3931
   consume(tCOMMA);
23✔
3932

3933
   do {
40✔
3934
      vlog_add_param(v, p_expression());
40✔
3935
   } while (optional(tCOMMA));
40✔
3936

3937
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
23✔
3938

3939
   consume(tRPAREN);
23✔
3940

3941
   vlog_set_loc(v, CURRENT_LOC);
23✔
3942
   return v;
23✔
3943
}
3944

3945
static void p_gate_instantiation(vlog_node_t mod)
45✔
3946
{
3947
   // cmos_switchtype [ delay3 ] cmos_switch_instance
3948
   //     { , cmos_switch_instance } ;
3949
   //  | enable_gatetype [ drive_strength ] [ delay3 ]
3950
   //     enable_gate_instance { , enable_gate_instance } ;
3951
   //  | mos_switchtype [ delay3 ] mos_switch_instance
3952
   //     { , mos_switch_instance } ;
3953
   //  | n_input_gatetype [ drive_strength ] [ delay2 ] n_input_gate_instance
3954
   //     { , n_input_gate_instance } ;
3955
   //  | n_output_gatetype [ drive_strength ] [ delay2 ] n_output_gate_instance
3956
   //     { , n_output_gate_instance } ;
3957
   //  | pass_en_switchtype [ delay2 ] pass_enable_switch_instance
3958
   //     { , pass_enable_switch_instance } ;
3959
   //  | pass_switchtype pass_switch_instance { , pass_switch_instance } ;
3960
   //  | pulldown [ pulldown_strength ] pull_gate_instance
3961
   //     { , pull_gate_instance } ;
3962
   //  | pullup [ pullup_strength ] pull_gate_instance
3963
   //     { , pull_gate_instance } ;
3964

3965
   BEGIN("gate instantiation");
90✔
3966

3967
   switch (one_of(tPULLDOWN, tPULLUP, tAND, tNAND, tOR, tNOR, tXOR, tXNOR,
45✔
3968
                  tNOT, tBUF)) {
3969
   case tPULLDOWN:
8✔
3970
      {
3971
         vlog_node_t st;
8✔
3972
         if (peek() == tLPAREN && peek_nth(2) != tID)
8✔
3973
            st = p_pulldown_strength();
2✔
3974
         else {
3975
            st = vlog_new(V_STRENGTH);
6✔
3976
            vlog_set_subkind(st, ST_PULLUP);
6✔
3977
         }
3978

3979
         do {
8✔
3980
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLDOWN, st);
8✔
3981
            vlog_add_stmt(mod, g);
8✔
3982
         } while (optional(tCOMMA));
8✔
3983
      }
3984
      break;
3985

3986
   case tPULLUP:
14✔
3987
      {
3988
         vlog_node_t st;
14✔
3989
         if (peek() == tLPAREN && peek_nth(2) != tID)
14✔
3990
            st = p_pullup_strength();
7✔
3991
         else {
3992
            st = vlog_new(V_STRENGTH);
7✔
3993
            vlog_set_subkind(st, ST_PULLUP);
7✔
3994
         }
3995

3996
         do {
14✔
3997
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLUP, st);
14✔
3998
            vlog_add_stmt(mod, g);
14✔
3999
         } while (optional(tCOMMA));
14✔
4000
      }
4001
      break;
4002

4003
   case tAND:
5✔
4004
      do {
5✔
4005
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_AND));
5✔
4006
      } while (optional(tCOMMA));
5✔
4007
      break;
4008

4009
   case tNAND:
4✔
4010
      do {
4✔
4011
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_NAND));
4✔
4012
      } while (optional(tCOMMA));
4✔
4013
      break;
4014

4015
   case tOR:
5✔
4016
      do {
5✔
4017
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_OR));
5✔
4018
      } while (optional(tCOMMA));
5✔
4019
      break;
4020

4021
   case tNOR:
×
4022
      do {
×
4023
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_NOR));
×
4024
      } while (optional(tCOMMA));
×
4025
      break;
4026

4027
   case tXOR:
4✔
4028
      do {
4✔
4029
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_XOR));
4✔
4030
      } while (optional(tCOMMA));
4✔
4031
      break;
4032

4033
   case tXNOR:
×
4034
      do {
×
4035
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_XNOR));
×
4036
      } while (optional(tCOMMA));
×
4037
      break;
4038

4039
   case tNOT:
4✔
4040
      do {
4✔
4041
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_NOT));
4✔
4042
      } while (optional(tCOMMA));
4✔
4043
      break;
4044

4045
   case tBUF:
1✔
4046
      do {
1✔
4047
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_BUF));
1✔
4048
      } while (optional(tCOMMA));
1✔
4049
      break;
4050

4051
   default:
4052
      break;
4053
   }
4054

4055
   consume(tSEMI);
45✔
4056
}
45✔
4057

4058
static vlog_node_t p_module_path_expression(void)
4✔
4059
{
4060
   // module_path_primary
4061
   //   | unary_module_path_operator { attribute_instance } module_path_primary
4062
   //   | module_path_expression binary_module_path_operator
4063
   //      { attribute_instance } module_path_expression
4064
   //   | module_path_conditional_expression
4065

4066
   BEGIN("module path expression");
8✔
4067

4068
   // TODO: sem should check valid subset
4069
   return p_expression();
4✔
4070
}
4071

4072
static void p_path_delay_expression(void)
19✔
4073
{
4074
   // constant_expression
4075
   //   | constant_expression : constant_expression : constant_expression
4076

4077
   BEGIN("path delay expression");
38✔
4078

4079
   (void)p_constant_expression();
19✔
4080
}
19✔
4081

4082
static void p_list_of_path_delay_expressions(void)
15✔
4083
{
4084
   // path_delay_expression { , path_delay_expression }
4085

4086
   BEGIN("list of path delay expressions");
30✔
4087

4088
   do {
19✔
4089
      p_path_delay_expression();
19✔
4090
   } while (optional(tCOMMA));
19✔
4091
}
15✔
4092

4093
static void p_path_delay_value(void)
15✔
4094
{
4095
   // list_of_path_delay_expressions | ( list_of_path_delay_expressions )
4096

4097
   BEGIN("path delay value");
30✔
4098

4099
   if (optional(tLPAREN)) {
15✔
4100
      p_list_of_path_delay_expressions();
4✔
4101
      consume(tRPAREN);
4✔
4102
   }
4103
   else
4104
      p_list_of_path_delay_expressions();
11✔
4105
}
15✔
4106

4107
static vlog_node_t p_specify_terminal_descriptor(void)
67✔
4108
{
4109
   // identifier [ [ constant_range_expression ] ]
4110

4111
   BEGIN("specify terminal descriptor");
67✔
4112

4113
   vlog_node_t v = vlog_new(V_REF);
67✔
4114
   vlog_set_ident(v, p_identifier());
67✔
4115
   vlog_set_loc(v, CURRENT_LOC);
67✔
4116

4117
   if (optional(tLSQUARE)) {
67✔
4118
      (void)p_constant_range_expression();
2✔
4119
      consume(tRSQUARE);
2✔
4120
   }
4121

4122
   return v;
67✔
4123
}
4124

4125
static void p_list_of_path_inputs(vlog_node_t v, vlog_node_t head)
8✔
4126
{
4127
   // specify_input_terminal_descriptor { , specify_input_terminal_descriptor }
4128

4129
   BEGIN_WITH_HEAD("list of path inputs", head);
16✔
4130

4131
   while (optional(tCOMMA))
15✔
4132
      (void)p_specify_terminal_descriptor();
7✔
4133
}
8✔
4134

4135
static void p_list_of_path_outputs(vlog_node_t v)
8✔
4136
{
4137
   // specify_output_terminal_descriptor
4138
   //     { , specify_output_terminal_descriptor }
4139

4140
   BEGIN("list of path outputs");
16✔
4141

4142
   do {
17✔
4143
      (void)p_specify_terminal_descriptor();
17✔
4144
   } while (optional(tCOMMA));
17✔
4145
}
8✔
4146

4147
static void p_polarity_operator(void)
7✔
4148
{
4149
   // + | -
4150

4151
   BEGIN("polarity operator");
14✔
4152

4153
   (void)one_of(tPLUS, tMINUS);
7✔
4154
}
7✔
4155

4156
static vlog_node_t p_parallel_path_description(vlog_node_t head)
5✔
4157
{
4158
   // ( specify_input_terminal_descriptor [ polarity_operator ]
4159
   //     => specify_output_terminal_descriptor )
4160

4161
   EXTEND("parallel path description");
5✔
4162

4163
   if (scan(tPLUS, tMINUS))
5✔
4164
      (void)p_polarity_operator();
1✔
4165

4166
   consume(tASSOC);
5✔
4167

4168
   (void)p_specify_terminal_descriptor();
5✔
4169

4170
   consume(tRPAREN);
5✔
4171
   return NULL;
5✔
4172
}
4173

4174
static vlog_node_t p_full_path_description(vlog_node_t head)
3✔
4175
{
4176
   // ( list_of_path_inputs [ polarity_operator ] *> list_of_path_outputs )
4177

4178
   EXTEND("full path description");
3✔
4179

4180
   p_list_of_path_inputs(NULL, head);
3✔
4181

4182
   if (scan(tPLUS, tMINUS))
3✔
4183
      (void)p_polarity_operator();
3✔
4184

4185
   consume(tTIMESGT);
3✔
4186

4187
   p_list_of_path_outputs(NULL);
3✔
4188

4189
   consume(tRPAREN);
3✔
4190
   return NULL;
3✔
4191
}
4192

4193
static vlog_node_t p_simple_path_declaration(void)
8✔
4194
{
4195
   // parallel_path_description = path_delay_value
4196
   //   | full_path_description = path_delay_value
4197

4198
   BEGIN("simple path declaration");
8✔
4199

4200
   // Parse up to the first terminal descriptor to determine which
4201
   // production to use
4202

4203
   consume(tLPAREN);
8✔
4204

4205
   vlog_node_t head = p_specify_terminal_descriptor();
8✔
4206

4207
   if (scan(tCOMMA, tTIMESGT) || peek_nth(2) == tTIMESGT)
8✔
4208
      (void)p_full_path_description(head);
3✔
4209
   else
4210
      (void)p_parallel_path_description(head);
5✔
4211

4212
   consume(tEQ);
8✔
4213

4214
   (void)p_path_delay_value();
8✔
4215

4216
   return NULL;
8✔
4217
}
4218

4219
static void p_edge_identifier(void)
7✔
4220
{
4221
   // posedge | negedge | edge
4222

4223
   BEGIN("edge identifier");
14✔
4224

4225
   one_of(tPOSEDGE, tNEGEDGE, tEDGE);
7✔
4226
}
7✔
4227

4228
static vlog_node_t p_parallel_edge_sensitive_path_description(vlog_node_t head)
2✔
4229
{
4230
   // ( [ edge_identifier ] specify_input_terminal_descriptor
4231
   //     [ polarity_operator ] => ( specify_output_terminal_descriptor
4232
   //     [ polarity_operator ] : data_source_expression ) )
4233

4234
   EXTEND("parallel edge sensitive path description");
2✔
4235

4236
   if (scan(tPLUS, tMINUS))
2✔
4237
      (void)p_polarity_operator();
×
4238

4239
   consume(tASSOC);
2✔
4240

4241
   consume(tLPAREN);
2✔
4242

4243
   (void)p_specify_terminal_descriptor();
2✔
4244

4245
   if (scan(tPLUS, tMINUS)) {
2✔
4246
      (void)p_polarity_operator();
×
4247
      consume(tCOLON);
×
4248
   }
4249
   else if (scan(tINDEXPOS, tINDEXNEG))
2✔
4250
      consume(peek());  // Lexing ambiguity with +: and -:
1✔
4251
   else
4252
      consume(tCOLON);
1✔
4253

4254
   (void)p_expression();
2✔
4255

4256
   consume(tRPAREN);
2✔
4257
   consume(tRPAREN);
2✔
4258
   return NULL;
2✔
4259
}
4260

4261
static vlog_node_t p_full_edge_sensitive_path_description(vlog_node_t head)
5✔
4262
{
4263
   // ( [ edge_identifier ] list_of_path_inputs [ polarity_operator ] *>
4264
   //     ( list_of_path_outputs [ polarity_operator ]
4265
   //     : data_source_expression ) )
4266

4267
   EXTEND("full edge sensitive path description");
5✔
4268

4269
   p_list_of_path_inputs(NULL, head);
5✔
4270

4271
   if (scan(tPLUS, tMINUS))
5✔
4272
      (void)p_polarity_operator();
3✔
4273

4274
   consume(tTIMESGT);
5✔
4275

4276
   consume(tLPAREN);
5✔
4277

4278
   p_list_of_path_outputs(NULL);
5✔
4279

4280
   if (scan(tPLUS, tMINUS)) {
5✔
4281
      (void)p_polarity_operator();
×
4282
      consume(tCOLON);
×
4283
   }
4284
   else if (scan(tINDEXPOS, tINDEXNEG))
5✔
4285
      consume(peek());  // Lexing ambiguity with +: and -:
2✔
4286
   else
4287
      consume(tCOLON);
3✔
4288

4289
   (void)p_expression();
5✔
4290

4291
   consume(tRPAREN);
5✔
4292
   consume(tRPAREN);
5✔
4293
   return NULL;
5✔
4294
}
4295

4296
static vlog_node_t p_edge_sensitive_path_declaration(void)
7✔
4297
{
4298
   // parallel_edge_sensitive_path_description = path_delay_value
4299
   //   | full_edge_sensitive_path_description = path_delay_value
4300

4301
   BEGIN("edge sensitive path declaration");
7✔
4302

4303
   // Parse up to the first terminal descriptor to determine which
4304
   // production to use
4305

4306
   consume(tLPAREN);
7✔
4307

4308
   if (scan(tEDGE, tPOSEDGE, tNEGEDGE))
7✔
4309
      p_edge_identifier();
7✔
4310

4311
   vlog_node_t head = p_specify_terminal_descriptor();
7✔
4312

4313
   if (scan(tCOMMA, tTIMESGT) || peek_nth(2) == tTIMESGT)
7✔
4314
      (void)p_full_edge_sensitive_path_description(head);
5✔
4315
   else
4316
      (void)p_parallel_edge_sensitive_path_description(head);
2✔
4317

4318
   consume(tEQ);
7✔
4319

4320
   (void)p_path_delay_value();
7✔
4321

4322
   return NULL;
7✔
4323
}
4324

4325
static vlog_node_t p_state_dependent_path_declaration(void)
6✔
4326
{
4327
   // if ( module_path_expression ) simple_path_declaration
4328
   //   | if ( module_path_expression ) edge_sensitive_path_declaration
4329
   //   | ifnone simple_path_declaration
4330

4331
   BEGIN("state dependent path declaration");
6✔
4332

4333
   switch (one_of(tIF, tIFNONE)) {
6✔
4334
   case tIF:
4✔
4335
      consume(tLPAREN);
4✔
4336
      (void)p_module_path_expression();
4✔
4337
      consume(tRPAREN);
4✔
4338
      break;
4✔
4339
   case tIFNONE:
4340
      break;
4341
   }
4342

4343
   if (peek_nth(2) == tID)
6✔
4344
      (void)p_simple_path_declaration();
2✔
4345
   else {
4346
      // This is invalid for ifnone according to the grammar but is
4347
      // accepted by some simulators and seen in the wild
4348
      (void)p_edge_sensitive_path_declaration();
4✔
4349
   }
4350

4351
   return NULL;
6✔
4352
}
4353

4354
static vlog_node_t p_path_declaration(void)
15✔
4355
{
4356
   // simple_path_declaration ;
4357
   //  | edge_sensitive_path_declaration ;
4358
   //  | state_dependent_path_declaration ;
4359

4360
   BEGIN("path declaration");
15✔
4361

4362
   switch (peek()) {
15✔
4363
   case tIF:
6✔
4364
   case tIFNONE:
4365
      (void)p_state_dependent_path_declaration();
6✔
4366
      break;
6✔
4367
   case tLPAREN:
9✔
4368
      switch (peek_nth(2)) {
9✔
4369
      case tEDGE:
3✔
4370
      case tNEGEDGE:
4371
      case tPOSEDGE:
4372
         (void)p_edge_sensitive_path_declaration();
3✔
4373
         break;
3✔
4374
      default:
6✔
4375
         (void)p_simple_path_declaration();
6✔
4376
         break;
6✔
4377
      }
4378
      break;
4379
   default:
×
4380
      one_of(tIF, tIFNONE);
×
4381
   }
4382

4383
   consume(tSEMI);
15✔
4384
   return NULL;
15✔
4385
}
4386

4387
static void p_timing_check_event_control(void)
5✔
4388
{
4389
   // posedge | negedge | edge | edge_control_specifier
4390

4391
   BEGIN("timing check event control");
10✔
4392

4393
   one_of(tPOSEDGE, tNEGEDGE, tEDGE);
5✔
4394
}
5✔
4395

4396
static void p_scalar_timing_check_condition(void)
4✔
4397
{
4398
   //    expression
4399
   // | ~ expression
4400
   // | expression == scalar_constant
4401
   // | expression === scalar_constant
4402
   // | expression != scalar_constant
4403
   // | expression !== scalar_constant
4404

4405
   BEGIN("scalar timing check condition")
8✔
4406

4407
   p_expression();
4✔
4408
}
4✔
4409

4410
static void p_timing_check_condition(void)
4✔
4411
{
4412
   //     scalar_timing_check_condition
4413
   // | ( scalar_timing_check_condition )
4414

4415
   BEGIN("timing check condition");
8✔
4416

4417
   if (optional(tLPAREN)) {
4✔
4418
      p_scalar_timing_check_condition();
1✔
4419
      consume(tRPAREN);
1✔
4420
   }
4421
   else
4422
      p_scalar_timing_check_condition();
3✔
4423
}
4✔
4424

4425
static vlog_node_t p_timing_check_event(void)
20✔
4426
{
4427
   // [ timing_check_event_control ] specify_terminal_descriptor
4428
   //    [ &&& timing_check_condition ]
4429

4430
   BEGIN("timing check event");
20✔
4431

4432
   if (scan(tEDGE, tPOSEDGE, tNEGEDGE))
20✔
4433
      p_timing_check_event_control();
4✔
4434

4435
   (void)p_specify_terminal_descriptor();
20✔
4436

4437
   if (optional(tTRPLAMP))
20✔
4438
      p_timing_check_condition();
4✔
4439

4440
   return NULL;
20✔
4441
}
4442

4443
static vlog_node_t p_controlled_timing_check_event(void)
1✔
4444
{
4445
   // timing_check_event_control specify_terminal_descriptor
4446
   //    [ &&& timing_check_condition ]
4447

4448
   BEGIN("controlled timing check event");
1✔
4449

4450
   p_timing_check_event_control();
1✔
4451

4452
   (void)p_specify_terminal_descriptor();
1✔
4453

4454
   if (optional(tTRPLAMP))
1✔
4455
      p_timing_check_condition();
×
4456

4457
   return NULL;
1✔
4458
}
4459

4460
static vlog_node_t p_setup_or_hold_timing_check(void)
6✔
4461
{
4462
   // $setup ( data_event , reference_event , timing_check_limit
4463
   //   [ , [ notifier ] ] ) ;
4464
   //
4465
   // $hold ( reference_event , data_event , timing_check_limit
4466
   //   [ , [ notifier ] ] ) ;
4467

4468
   BEGIN("setup/hold timing check");
6✔
4469

4470
   one_of(tDLRSETUP, tDLRHOLD);
6✔
4471
   consume(tLPAREN);
6✔
4472

4473
   (void)p_timing_check_event();
6✔
4474

4475
   consume(tCOMMA);
6✔
4476

4477
   (void)p_timing_check_event();
6✔
4478

4479
   consume(tCOMMA);
6✔
4480

4481
   (void)p_expression();
6✔
4482

4483
   if (optional(tCOMMA)) {
6✔
4484
      if (peek() == tID)
4✔
4485
         p_identifier();
2✔
4486
   }
4487

4488
   consume(tRPAREN);
6✔
4489
   consume(tSEMI);
6✔
4490

4491
   return NULL;
6✔
4492
}
4493

4494
static vlog_node_t p_recovery_or_removal_timing_check(void)
2✔
4495
{
4496
   // $recovery ( reference_event , data_event , timing_check_limit
4497
   //   [ , [ notifier ] ] ) ;
4498
   //
4499
   // $removal ( reference_event , data_event , timing_check_limit
4500
   //   [ , [ notifier ] ] ) ;
4501

4502
   BEGIN("recovery/removal timing check");
2✔
4503

4504
   one_of(tDLRRECOVERY, tDLRREMOVAL);
2✔
4505
   consume(tLPAREN);
2✔
4506

4507
   (void)p_timing_check_event();
2✔
4508

4509
   consume(tCOMMA);
2✔
4510

4511
   (void)p_timing_check_event();
2✔
4512

4513
   consume(tCOMMA);
2✔
4514

4515
   (void)p_expression();
2✔
4516

4517
   if (optional(tCOMMA)) {
2✔
4518
      if (peek() == tID)
×
4519
         p_identifier();
×
4520
   }
4521

4522
   consume(tRPAREN);
2✔
4523
   consume(tSEMI);
2✔
4524

4525
   return NULL;
2✔
4526
}
4527

4528
static vlog_node_t p_width_timing_check(void)
1✔
4529
{
4530
   // $width ( controlled_reference_event , timing_check_limit , threshold
4531
   //   [ , [ notifier ] ] ) ;
4532

4533
   BEGIN("width timing check");
1✔
4534

4535
   consume(tDLRWIDTH);
1✔
4536
   consume(tLPAREN);
1✔
4537

4538
   (void)p_controlled_timing_check_event();
1✔
4539

4540
   consume(tCOMMA);
1✔
4541

4542
   (void)p_expression();
1✔
4543

4544
   consume(tCOMMA);
1✔
4545

4546
   (void)p_constant_expression();
1✔
4547

4548
   if (optional(tCOMMA)) {
1✔
4549
      if (peek() == tID)
×
4550
         p_identifier();
×
4551
   }
4552

4553
   consume(tRPAREN);
1✔
4554
   consume(tSEMI);
1✔
4555

4556
   return NULL;
1✔
4557
}
4558

4559
static vlog_node_t p_delayed_data_or_reference(void)
2✔
4560
{
4561
   // terminal_identifier
4562
   //   | terminal_identifier [ constant_mintypmax_expression ]
4563

4564
   BEGIN("delayed data/reference");
2✔
4565

4566
   p_identifier();
2✔
4567

4568
   return NULL;
2✔
4569
}
4570

4571
static vlog_node_t p_setuphold_or_recrem_timing_check(void)
2✔
4572
{
4573
   // $setuphold ( reference_event , data_event , timing_check_limit ,
4574
   //    timing_check_limit [ , [ notifier ] [ , [ timestamp_condition ]
4575
   //    [ , [ timecheck_condition ] [ , [ delayed_reference ]
4576
   //    [ , [ delayed_data ] ] ] ] ] ] ) ;
4577

4578
   BEGIN("setuphold/recrem timing check");
2✔
4579

4580
   one_of(tDLRSETUPHOLD, tDLRRECREM);
2✔
4581
   consume(tLPAREN);
2✔
4582

4583
   (void)p_timing_check_event();
2✔
4584

4585
   consume(tCOMMA);
2✔
4586

4587
   (void)p_timing_check_event();
2✔
4588

4589
   consume(tCOMMA);
2✔
4590

4591
   (void)p_expression();
2✔
4592

4593
   consume(tCOMMA);
2✔
4594

4595
   (void)p_expression();
2✔
4596

4597
   if (optional(tCOMMA)) {
2✔
4598
      if (peek() == tID)
2✔
4599
         p_identifier(); // notifier
2✔
4600

4601
      if (optional(tCOMMA)) {
2✔
4602
         if (not_at_token(tCOMMA, tRPAREN))
2✔
4603
            (void)p_mintypmax_expression();  // timestamp_condition
×
4604

4605
         if (optional(tCOMMA)) {
2✔
4606
            if (not_at_token(tCOMMA, tRPAREN))
2✔
4607
               (void)p_mintypmax_expression();  // timecheck_condition
×
4608

4609
            if (optional(tCOMMA)) {
2✔
4610
               if (not_at_token(tCOMMA, tRPAREN))
2✔
4611
                  p_delayed_data_or_reference();  // delayed_reference
1✔
4612

4613
               if (optional(tCOMMA)) {
2✔
4614
                  if (not_at_token(tCOMMA, tRPAREN))
2✔
4615
                     p_delayed_data_or_reference();  // delayed_data
1✔
4616
               }
4617
            }
4618
         }
4619
      }
4620
   }
4621

4622
   consume(tRPAREN);
2✔
4623
   consume(tSEMI);
2✔
4624

4625
   return NULL;
2✔
4626
}
4627

4628
static vlog_node_t p_system_timing_check(void)
11✔
4629
{
4630
   // $setup_timing_check | $hold_timing_check | $setuphold_timing_check
4631
   //   | $recovery_timing_check | $removal_timing_check | $recrem_timing_check
4632
   //   | $skew_timing_check | $timeskew_timing_check | $fullskew_timing_check
4633
   //   | $period_timing_check | $width_timing_check | $nochange_timing_check
4634

4635
   BEGIN("system timing check");
22✔
4636

4637
   switch (peek()) {
11✔
4638
   case tDLRSETUP:
6✔
4639
   case tDLRHOLD:
4640
      return p_setup_or_hold_timing_check();
6✔
4641
   case tDLRRECOVERY:
2✔
4642
   case tDLRREMOVAL:
4643
      return p_recovery_or_removal_timing_check();
2✔
4644
   case tDLRWIDTH:
1✔
4645
      return p_width_timing_check();
1✔
4646
   case tDLRSETUPHOLD:
2✔
4647
   case tDLRRECREM:
4648
      return p_setuphold_or_recrem_timing_check();
2✔
4649
   default:
×
4650
      should_not_reach_here();
4651
   }
4652
}
4653

4654
static vlog_node_t p_specparam_assignment(void)
2✔
4655
{
4656
   // specparam_identifier = constant_mintypmax_expression
4657
   //    | pulse_control_specparam
4658

4659
   BEGIN("specparam assignment");
2✔
4660

4661
   vlog_node_t v = vlog_new(V_SPECPARAM);
2✔
4662
   vlog_set_ident(v, p_identifier());
2✔
4663

4664
   consume(tEQ);
2✔
4665

4666
   vlog_set_value(v, p_constant_mintypmax_expression());
2✔
4667

4668
   vlog_set_loc(v, CURRENT_LOC);
2✔
4669
   vlog_symtab_put(symtab, v);
2✔
4670
   return v;
2✔
4671
}
4672

4673
static void p_list_of_specparam_assignments(vlog_node_t parent)
2✔
4674
{
4675
   // specparam_assignment { , specparam_assignment }
4676

4677
   BEGIN("list of specparam assignments");
4✔
4678

4679
   do {
2✔
4680
      vlog_add_decl(parent, p_specparam_assignment());
2✔
4681
   } while (optional(tCOMMA));
2✔
4682
}
2✔
4683

4684
static void p_specparam_declaration(vlog_node_t parent)
2✔
4685
{
4686
   // specparam [ packed_dimension ] list_of_specparam_assignments ;
4687

4688
   BEGIN("specparam declaration");
4✔
4689

4690
   consume(tSPECPARAM);
2✔
4691

4692
   if (peek() == tLSQUARE)
2✔
4693
      (void)p_packed_dimension();
1✔
4694

4695
   p_list_of_specparam_assignments(parent);
2✔
4696

4697
   consume(tSEMI);
2✔
4698
}
2✔
4699

4700
static void p_specify_item(vlog_node_t parent)
28✔
4701
{
4702
   // specparam_declaration | pulsestyle_declaration | showcancelled_declaration
4703
   //   | path_declaration | system_timing_check
4704

4705
   BEGIN("specify item");
56✔
4706

4707
   switch (peek()) {
28✔
4708
   case tSPECPARAM:
2✔
4709
      p_specparam_declaration(parent);
2✔
4710
      break;
2✔
4711
   case tLPAREN:
15✔
4712
   case tIF:
4713
   case tIFNONE:
4714
      (void)p_path_declaration();
15✔
4715
      break;
15✔
4716
   case tDLRSETUP:
11✔
4717
   case tDLRHOLD:
4718
   case tDLRRECOVERY:
4719
   case tDLRREMOVAL:
4720
   case tDLRSETUPHOLD:
4721
   case tDLRRECREM:
4722
   case tDLRWIDTH:
4723
      (void)p_system_timing_check();
11✔
4724
      break;
11✔
4725
   default:
×
4726
      one_of(tSPECPARAM, tLPAREN, tIF, tIFNONE, tDLRSETUP, tDLRHOLD,
×
4727
             tDLRRECOVERY, tDLRREMOVAL, tDLRSETUPHOLD, tDLRRECREM,
4728
             tDLRWIDTH);
4729
   }
4730
}
28✔
4731

4732
static vlog_node_t p_specify_block(void)
1✔
4733
{
4734
   // specify { specify_item } endspecify
4735

4736
   BEGIN("specify block");
1✔
4737

4738
   consume(tSPECIFY);
1✔
4739

4740
   vlog_node_t v = vlog_new(V_SPECIFY);
1✔
4741
   vlog_set_loc(v, CURRENT_LOC);
1✔
4742

4743
   vlog_symtab_push(symtab, v);
1✔
4744

4745
   while (not_at_token(tENDSPECIFY))
29✔
4746
      p_specify_item(v);
28✔
4747

4748
   vlog_symtab_pop(symtab);
1✔
4749

4750
   consume(tENDSPECIFY);
1✔
4751

4752
   vlog_set_loc(v, CURRENT_LOC);
1✔
4753
   return v;
1✔
4754
}
4755

4756
static vlog_node_t p_ordered_port_connection(void)
66✔
4757
{
4758
   // { attribute_instance } [ expression ]
4759

4760
   BEGIN("ordered port connection");
66✔
4761

4762
   vlog_node_t v = vlog_new(V_PORT_CONN);
66✔
4763

4764
   if (not_at_token(tCOMMA, tRPAREN))
66✔
4765
      vlog_set_value(v, p_expression());
66✔
4766

4767
   vlog_set_loc(v, CURRENT_LOC);
66✔
4768
   return v;
66✔
4769
}
4770

4771
static vlog_node_t p_named_port_connection(void)
1✔
4772
{
4773
   // { attribute_instance } . port_identifier [ ( [ expression ] ) ]
4774
   //    | { attribute_instance } .*
4775

4776
   BEGIN("named port connection");
1✔
4777

4778
   vlog_node_t v = vlog_new(V_PORT_CONN);
1✔
4779

4780
   consume(tDOT);
1✔
4781

4782
   vlog_set_ident(v, p_identifier());
1✔
4783

4784
   if (optional(tLPAREN)) {
1✔
4785

4786
      if (peek() != tRPAREN)
1✔
4787
         vlog_set_value(v, p_expression());
1✔
4788

4789
      consume(tRPAREN);
1✔
4790
   }
4791

4792
   vlog_set_loc(v, CURRENT_LOC);
1✔
4793
   return v;
1✔
4794
}
4795

4796
static void p_list_of_port_connections(vlog_node_t inst)
46✔
4797
{
4798
   // ordered_port_connection { , ordered_port_connection }
4799
   //   | named_port_connection { , named_port_connection }
4800

4801
   BEGIN("list of port connections");
92✔
4802

4803
   vlog_symtab_set_implicit(symtab, implicit_kind);
46✔
4804

4805
   do {
67✔
4806
      if (peek() == tDOT)
67✔
4807
         vlog_add_param(inst, p_named_port_connection());
1✔
4808
      else
4809
         vlog_add_param(inst, p_ordered_port_connection());
66✔
4810
   } while (optional(tCOMMA));
67✔
4811

4812
   vlog_symtab_set_implicit(symtab, V_NET_NONE);
46✔
4813
}
46✔
4814

4815
static vlog_node_t p_hierarchical_instance(void)
48✔
4816
{
4817
   // name_of_instance ( [ list_of_port_connections ] )
4818

4819
   BEGIN("hierarchical instance");
48✔
4820

4821
   vlog_node_t v = vlog_new(V_MOD_INST);
48✔
4822
   vlog_set_ident(v, p_identifier());
48✔
4823

4824
   consume(tLPAREN);
48✔
4825

4826
   if (peek() != tRPAREN)
48✔
4827
      p_list_of_port_connections(v);
45✔
4828

4829
   consume(tRPAREN);
48✔
4830

4831
   vlog_set_loc(v, CURRENT_LOC);
48✔
4832
   vlog_symtab_put(symtab, v);
48✔
4833
   return v;
48✔
4834
}
4835

4836
static vlog_node_t p_udp_instance(void)
1✔
4837
{
4838
   // [ name_of_instance ] ( output_terminal , input_terminal
4839
   //   { , input_terminal } )
4840

4841
   BEGIN("udp instance");
1✔
4842

4843
   vlog_node_t v = vlog_new(V_MOD_INST);
1✔
4844
   if (peek() == tID)
1✔
4845
      vlog_set_ident(v, p_identifier());
×
4846
   else
4847
      vlog_set_ident(v, ident_uniq("$unnamed"));
1✔
4848

4849
   consume(tLPAREN);
1✔
4850

4851
   p_list_of_port_connections(v);
1✔
4852

4853
   consume(tRPAREN);
1✔
4854

4855
   vlog_set_loc(v, CURRENT_LOC);
1✔
4856
   return v;
1✔
4857
}
4858

4859
static vlog_node_t p_param_expression(void)
30✔
4860
{
4861
   // mintypmax_expression | data_type | $
4862

4863
   BEGIN("param expression");
60✔
4864

4865
   return p_expression();   // TODO
30✔
4866
}
4867

4868
static vlog_node_t p_named_parameter_assignment(void)
2✔
4869
{
4870
   // . parameter_identifier ( [ param_expression ] )
4871

4872
   BEGIN("named parameter assignment");
2✔
4873

4874
   consume(tDOT);
2✔
4875

4876
   vlog_node_t v = vlog_new(V_PARAM_ASSIGN);
2✔
4877
   vlog_set_ident(v, p_identifier());
2✔
4878

4879
   consume(tLPAREN);
2✔
4880

4881
   if (peek() != tRPAREN)
2✔
4882
      vlog_set_value(v, p_param_expression());
2✔
4883

4884
   consume(tRPAREN);
2✔
4885

4886
   vlog_set_loc(v, CURRENT_LOC);
2✔
4887
   return v;
2✔
4888
}
4889

4890
static vlog_node_t p_ordered_parameter_assignment(void)
28✔
4891
{
4892
   // param_expression
4893

4894
   BEGIN("ordered parameter assignment");
28✔
4895

4896
   vlog_node_t v = vlog_new(V_PARAM_ASSIGN);
28✔
4897
   vlog_set_value(v, p_param_expression());
28✔
4898

4899
   vlog_set_loc(v, CURRENT_LOC);
28✔
4900
   return v;
28✔
4901
}
4902

4903
static void p_list_of_parameter_assignments(vlog_node_t inst)
28✔
4904
{
4905
   // ordered_parameter_assignment { , ordered_parameter_assignment }
4906
   //   | named_parameter_assignment { , named_parameter_assignment }
4907

4908
   BEGIN("list of parameter assignments");
56✔
4909

4910
   do {
30✔
4911
      if (peek() == tDOT)
30✔
4912
         vlog_add_param(inst, p_named_parameter_assignment());
2✔
4913
      else
4914
         vlog_add_param(inst, p_ordered_parameter_assignment());
28✔
4915
   } while (optional(tCOMMA));
30✔
4916
}
28✔
4917

4918
static void p_parameter_value_assignment(vlog_node_t inst)
28✔
4919
{
4920
   // # ( [ list_of_parameter_assignments ] )
4921

4922
   BEGIN("parameter value assignment");
56✔
4923

4924
   consume(tHASH);
28✔
4925
   consume(tLPAREN);
28✔
4926

4927
   if (peek() != tRPAREN)
28✔
4928
      p_list_of_parameter_assignments(inst);
28✔
4929

4930
   consume(tRPAREN);
28✔
4931
}
28✔
4932

4933
static void p_module_or_udp_instantiation(vlog_node_t mod)
47✔
4934
{
4935
   // module_identifier [ parameter_value_assignment ] hierarchical_instance
4936
   //   { , hierarchical_instance } ;
4937
   //
4938
   // udp_identifier [ drive_strength ] [ delay2 ] udp_instance
4939
   //   { , udp_instance } ;
4940

4941
   BEGIN("module instantiation");
94✔
4942

4943
   vlog_node_t v = vlog_new(V_INST_LIST);
47✔
4944
   vlog_set_ident(v, p_identifier());
47✔
4945

4946
   if (peek() == tHASH)
47✔
4947
      p_parameter_value_assignment(v);
28✔
4948

4949
   do {
49✔
4950
      if (peek() == tLPAREN)
49✔
4951
         vlog_add_stmt(v, p_udp_instance());
1✔
4952
      else
4953
         vlog_add_stmt(v, p_hierarchical_instance());
48✔
4954
   } while (optional(tCOMMA));
49✔
4955

4956
   consume(tSEMI);
47✔
4957

4958
   vlog_set_loc(v, CURRENT_LOC);
47✔
4959

4960
   vlog_add_stmt(mod, v);
47✔
4961
}
47✔
4962

4963
static void p_module_or_generate_item(vlog_node_t mod)
945✔
4964
{
4965
   // { attribute_instance } parameter_override
4966
   //   | { attribute_instance } gate_instantiation
4967
   //   | { attribute_instance } udp_instantiation
4968
   //   | { attribute_instance } module_instantiation
4969
   //   | { attribute_instance } module_common_item
4970

4971
   BEGIN("module or generate item");
1,890✔
4972

4973
   optional_attributes();
945✔
4974

4975
   switch (peek()) {
945✔
4976
   case tALWAYS:
851✔
4977
   case tALWAYSCOMB:
4978
   case tALWAYSFF:
4979
   case tALWAYSLATCH:
4980
   case tWIRE:
4981
   case tUWIRE:
4982
   case tSUPPLY0:
4983
   case tSUPPLY1:
4984
   case tTRI:
4985
   case tTRI0:
4986
   case tTRI1:
4987
   case tTRIAND:
4988
   case tTRIOR:
4989
   case tTRIREG:
4990
   case tWAND:
4991
   case tWOR:
4992
   case tINTERCONNECT:
4993
   case tREG:
4994
   case tSTRUCT:
4995
   case tUNION:
4996
   case tASSIGN:
4997
   case tINITIAL:
4998
   case tTYPEDEF:
4999
   case tENUM:
5000
   case tSVINT:
5001
   case tINTEGER:
5002
   case tSVREAL:
5003
   case tSHORTREAL:
5004
   case tREALTIME:
5005
   case tTIME:
5006
   case tTASK:
5007
   case tFUNCTION:
5008
   case tLOCALPARAM:
5009
   case tPARAMETER:
5010
   case tIF:
5011
   case tFOR:
5012
   case tEVENT:
5013
   case tGENVAR:
5014
      p_module_common_item(mod);
851✔
5015
      break;
851✔
5016
   case tPULLDOWN:
45✔
5017
   case tPULLUP:
5018
   case tAND:
5019
   case tNAND:
5020
   case tOR:
5021
   case tNOR:
5022
   case tXOR:
5023
   case tXNOR:
5024
   case tNOT:
5025
   case tBUF:
5026
      p_gate_instantiation(mod);
45✔
5027
      break;
45✔
5028
   case tID:
49✔
5029
      {
5030
         vlog_node_t ref = peek_reference();
49✔
5031
         if (ref == NULL)
49✔
5032
            p_module_or_udp_instantiation(mod);
47✔
5033
         else
5034
            p_module_common_item(mod);
2✔
5035
      }
5036
      break;
5037
   default:
×
5038
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
×
5039
             tSUPPLY0, tSUPPLY1, tTRI,  tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
5040
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tASSIGN,
5041
             tINITIAL, tTYPEDEF, tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL,
5042
             tREALTIME, tTIME, tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER, tIF,
5043
             tFOR, tEVENT, tGENVAR, tPULLDOWN, tPULLUP, tID, tAND, tNAND, tOR,
5044
             tNOR, tXOR, tXNOR, tNOT, tBUF);
UNCOV
5045
      drop_tokens_until(tSEMI);
×
5046
   }
5047
}
945✔
5048

5049
static void p_generate_region(vlog_node_t mod)
5✔
5050
{
5051
   // generate { generate_item } endgenerate
5052

5053
   BEGIN("generate region");
10✔
5054

5055
   // Has no real meaning in System Verilog
5056

5057
   // TODO: generate regions do not nest so check mod is V_MODULE
5058

5059
   consume(tGENERATE);
5✔
5060

5061
   while (not_at_token(tENDGENERATE))
10✔
5062
      p_generate_item(mod);
5✔
5063

5064
   consume(tENDGENERATE);
5✔
5065
}
5✔
5066

5067
static void p_non_port_module_item(vlog_node_t mod)
935✔
5068
{
5069
   // generate_region | module_or_generate_item | specify_block
5070
   //   | { attribute_instance } specparam_declaration | program_declaration
5071
   //   | module_declaration | interface_declaration | timeunits_declaration
5072

5073
   BEGIN("non-port module item");
1,870✔
5074

5075
   switch (peek()) {
935✔
5076
   case tALWAYS:
927✔
5077
   case tALWAYSCOMB:
5078
   case tALWAYSFF:
5079
   case tALWAYSLATCH:
5080
   case tWIRE:
5081
   case tUWIRE:
5082
   case tSUPPLY0:
5083
   case tSUPPLY1:
5084
   case tTRI:
5085
   case tTRI0:
5086
   case tTRI1:
5087
   case tTRIAND:
5088
   case tTRIOR:
5089
   case tTRIREG:
5090
   case tWAND:
5091
   case tWOR:
5092
   case tINTERCONNECT:
5093
   case tREG:
5094
   case tSTRUCT:
5095
   case tUNION:
5096
   case tASSIGN:
5097
   case tINITIAL:
5098
   case tPULLDOWN:
5099
   case tPULLUP:
5100
   case tID:
5101
   case tATTRBEGIN:
5102
   case tAND:
5103
   case tNAND:
5104
   case tOR:
5105
   case tNOR:
5106
   case tXOR:
5107
   case tXNOR:
5108
   case tNOT:
5109
   case tBUF:
5110
   case tTYPEDEF:
5111
   case tENUM:
5112
   case tSVINT:
5113
   case tINTEGER:
5114
   case tSVREAL:
5115
   case tSHORTREAL:
5116
   case tREALTIME:
5117
   case tTIME:
5118
   case tTASK:
5119
   case tFUNCTION:
5120
   case tLOCALPARAM:
5121
   case tPARAMETER:
5122
   case tEVENT:
5123
   case tIF:
5124
   case tFOR:
5125
   case tGENVAR:
5126
      p_module_or_generate_item(mod);
927✔
5127
      break;
927✔
5128
   case tSPECIFY:
1✔
5129
      vlog_add_stmt(mod, p_specify_block());
1✔
5130
      break;
1✔
5131
   case tGENERATE:
5✔
5132
      p_generate_region(mod);
5✔
5133
      break;
5✔
5134
   default:
2✔
5135
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tUWIRE,
2✔
5136
             tSUPPLY0, tSUPPLY1, tTRI, tTRI0, tTRI1, tTRIAND, tTRIOR, tTRIREG,
5137
             tWAND, tWOR, tINTERCONNECT, tREG, tSTRUCT, tUNION, tASSIGN,
5138
             tPULLDOWN, tPULLUP, tID, tATTRBEGIN, tAND, tNAND, tOR, tNOR, tXOR,
5139
             tXNOR, tNOT, tBUF, tTYPEDEF, tENUM, tSVINT, tINTEGER, tSVREAL,
5140
             tSHORTREAL, tREALTIME, tTIME, tTASK, tFUNCTION, tLOCALPARAM,
5141
             tPARAMETER, tEVENT, tIF, tFOR, tGENVAR, tSPECIFY, tGENERATE);
5142
      drop_tokens_until(tSEMI);
2✔
5143
   }
5144
}
935✔
5145

5146
static void p_module_item(vlog_node_t mod)
1,027✔
5147
{
5148
   // port_declaration ; | non_port_module_item
5149

5150
   BEGIN("module item");
2,054✔
5151

5152
   if (scan(tINOUT, tINPUT, tOUTPUT)) {
1,027✔
5153
      p_port_declaration(mod);
92✔
5154
      consume(tSEMI);
92✔
5155
   }
5156
   else
5157
      p_non_port_module_item(mod);
935✔
5158
}
1,027✔
5159

5160
static void p_ansi_port_declaration(vlog_node_t mod, v_port_kind_t *kind,
55✔
5161
                                    bool *isreg)
5162
{
5163
   // [ net_port_header | interface_port_header ] port_identifier
5164
   //     { unpacked_dimension } [ = constant_expression ]
5165
   // | [ variable_port_header ] port_identifier { variable_dimension }
5166
   //     [ = constant_expression ]
5167
   // | [ port_direction ] . port_identifier ( [ expression ] )
5168

5169
   BEGIN("ANSI port declaration");
110✔
5170

5171
   vlog_node_t dt;
55✔
5172
   if (peek() != tID)
55✔
5173
      dt = p_net_port_header(kind, isreg);
35✔
5174
   else
5175
      dt = logic_type();
20✔
5176

5177
   ident_t id, ext;
55✔
5178
   p_external_identifier(&id, &ext);
55✔
5179

5180
   vlog_node_t v = vlog_new(V_PORT_DECL);
55✔
5181
   vlog_set_subkind(v, *kind);
55✔
5182
   vlog_set_ident(v, id);
55✔
5183
   vlog_set_ident2(v, ext);
55✔
5184
   vlog_set_type(v, dt);
55✔
5185
   vlog_set_loc(v, &state.last_loc);
55✔
5186

5187
   vlog_add_decl(mod, v);
55✔
5188
   vlog_symtab_put(symtab, v);
55✔
5189

5190
   if (*isreg) {
55✔
5191
      vlog_node_t reg = vlog_new(V_VAR_DECL);
12✔
5192
      vlog_set_loc(reg, CURRENT_LOC);
12✔
5193
      vlog_set_ident(reg, id);
12✔
5194
      vlog_set_type(reg, dt);
12✔
5195

5196
      vlog_add_decl(mod, reg);
12✔
5197
      vlog_symtab_put(symtab, reg);
12✔
5198
   }
5199

5200
   vlog_node_t ref = vlog_new(V_REF);
55✔
5201
   vlog_set_loc(ref, CURRENT_LOC);
55✔
5202
   vlog_set_ident(ref, id);
55✔
5203
   vlog_set_ref(ref, v);
55✔
5204

5205
   vlog_add_port(mod, ref);
55✔
5206
}
55✔
5207

5208
static void p_list_of_port_declarations(vlog_node_t mod)
30✔
5209
{
5210
   // ( [ { attribute_instance } ansi_port_declaration
5211
   //   { , { attribute_instance } ansi_port_declaration } ] )
5212

5213
   BEGIN("list of port declarations");
60✔
5214

5215
   consume(tLPAREN);
30✔
5216

5217
   if (peek() != tRPAREN) {
30✔
5218
      v_port_kind_t kind = V_PORT_INPUT;
18✔
5219
      bool isreg = false;
18✔
5220
      do {
55✔
5221
         optional_attributes();
55✔
5222
         p_ansi_port_declaration(mod, &kind, &isreg);
55✔
5223
      } while (optional(tCOMMA));
55✔
5224
   }
5225

5226
   consume(tRPAREN);
30✔
5227
}
30✔
5228

5229
static void p_parameter_port_declaration(vlog_node_t mod)
4✔
5230
{
5231
   // parameter_declaration
5232
   //    | local_parameter_declaration
5233
   //    | data_type list_of_param_assignments
5234
   //    | type list_of_type_assignments
5235

5236
   BEGIN("parameter port declaration");
8✔
5237

5238
   switch (peek()) {
4✔
5239
   case tPARAMETER:
2✔
5240
      p_parameter_declaration(mod);
2✔
5241
      break;
2✔
5242
   case tLOCALPARAM:
1✔
5243
      p_local_parameter_declaration(mod);
1✔
5244
      break;
1✔
5245
   default:
1✔
5246
      // TODO: Add parsing of "type" declarations example #(type T = bit)
5247
      {
5248
         vlog_node_t datatype = p_data_type();
1✔
5249
         p_list_of_param_assignments(mod, datatype, V_PARAM_DECL);
1✔
5250
      }
5251
      break;
1✔
5252
   }
5253
}
4✔
5254

5255
static void p_parameter_port_list(vlog_node_t mod)
2✔
5256
{
5257
   // # ( list_of_param_assignments { , parameter_port_declaration } )
5258
   //    | # ( parameter_port_declaration { , parameter_port_declaration } )
5259
   //    | # ( )
5260

5261
   BEGIN("parameter port list");
4✔
5262

5263
   consume(tHASH);
2✔
5264
   consume(tLPAREN);
2✔
5265

5266
   if (peek() != tRPAREN) {
2✔
5267
      do {
5✔
5268
         if (peek() == tID)
5✔
5269
            p_list_of_param_assignments(mod, NULL, V_PARAM_DECL);
1✔
5270
         else
5271
            p_parameter_port_declaration(mod);
4✔
5272
      } while(optional(tCOMMA));
5✔
5273
   }
5274

5275
   consume(tRPAREN);
2✔
5276
}
2✔
5277

5278
static void p_module_ansi_header(vlog_node_t mod)
182✔
5279
{
5280
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
5281
   //    { package_import_declaration } [ parameter_port_list ]
5282
   ///   [ list_of_port_declarations ] ;
5283

5284
   EXTEND("module ANSI header");
364✔
5285

5286
   if (peek() == tHASH) {
182✔
5287
      p_parameter_port_list(mod);
2✔
5288
      param_kind = V_LOCALPARAM;
2✔
5289
   }
5290

5291
   if (peek() == tLPAREN)
182✔
5292
      p_list_of_port_declarations(mod);
30✔
5293

5294
   consume(tSEMI);
182✔
5295

5296
   vlog_set_loc(mod, CURRENT_LOC);
182✔
5297
}
182✔
5298

5299
static vlog_node_t p_port_reference(void)
101✔
5300
{
5301
   // port_identifier constant_select
5302

5303
   BEGIN("port reference");
101✔
5304

5305
   vlog_node_t v = vlog_new(V_REF);
101✔
5306
   vlog_set_ident(v, p_identifier());
101✔
5307
   vlog_set_loc(v, CURRENT_LOC);
101✔
5308
   return v;
101✔
5309
}
5310

5311
static vlog_node_t p_port_expression(void)
101✔
5312
{
5313
   // port_reference | { port_reference { , port_reference } }
5314

5315
   BEGIN("port expression");
202✔
5316

5317
   return p_port_reference();
101✔
5318
}
5319

5320
static vlog_node_t p_port(void)
101✔
5321
{
5322
   // [ port_expression ] | . port_identifier ( [ port_expression ] )
5323

5324
   BEGIN("port");
202✔
5325

5326
   return p_port_expression();
101✔
5327
}
5328

5329
static void p_list_of_ports(vlog_node_t mod)
41✔
5330
{
5331
   // ( port { , port } )
5332

5333
   BEGIN("list of ports");
82✔
5334

5335
   consume(tLPAREN);
41✔
5336

5337
   do {
101✔
5338
      p_port();
101✔
5339
   } while (optional(tCOMMA));
101✔
5340

5341
   consume(tRPAREN);
41✔
5342
}
41✔
5343

5344
static void p_module_nonansi_header(vlog_node_t mod)
41✔
5345
{
5346
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
5347
   //    { package_import_declaration } [ parameter_port_list ] list_of_ports ;
5348

5349
   EXTEND("module non-ANSI header");
82✔
5350

5351
   p_list_of_ports(mod);
41✔
5352

5353
   consume(tSEMI);
41✔
5354

5355
   vlog_set_loc(mod, CURRENT_LOC);
41✔
5356
}
41✔
5357

5358
static vlog_node_t p_module_declaration(void)
223✔
5359
{
5360
   // module_nonansi_header [ timeunits_declaration ] { module_item }
5361
   //      endmodule [ : module_identifier ]
5362
   //   | module_ansi_header [ timeunits_declaration ] { non_port_module_item }
5363
   //      endmodule [ : module_identifier ]
5364
   //   | { attribute_instance } module_keyword [ lifetime ] module_identifier
5365
   //      ( .* ) ; [ timeunits_declaration ] { module_item } endmodule
5366
   //      [ : module_identifier ]
5367
   //   | extern module_nonansi_header
5368
   //   | extern module_ansi_header
5369

5370
   BEGIN("module declaration");
223✔
5371

5372
   vlog_node_t mod = vlog_new(V_MODULE);
223✔
5373

5374
   optional_attributes();
223✔
5375

5376
   consume(tMODULE);
223✔
5377

5378
   ident_t id, ext;
223✔
5379
   p_external_identifier(&id, &ext);
223✔
5380
   vlog_set_ident2(mod, id);
223✔
5381

5382
   vlog_set_loc(mod, &state.last_loc);
223✔
5383

5384
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
223✔
5385
   vlog_set_ident(mod, qual);
223✔
5386

5387
   vlog_symtab_push(symtab, mod);
223✔
5388

5389
   if (peek() == tLPAREN && peek_nth(2) == tID)
223✔
5390
      p_module_nonansi_header(mod);
41✔
5391
   else
5392
      p_module_ansi_header(mod);
182✔
5393

5394
   while (not_at_token(tENDMODULE))
1,250✔
5395
      p_module_item(mod);
1,027✔
5396

5397
   consume(tENDMODULE);
223✔
5398

5399
   vlog_symtab_pop(symtab);
223✔
5400
   return mod;
223✔
5401
}
5402

5403
static void p_udp_port_list(vlog_node_t udp)
18✔
5404
{
5405
   // output_port_identifier , input_port_identifier { , input_port_identifier }
5406

5407
   BEGIN("UDP port list");
36✔
5408

5409
   vlog_node_t oref = vlog_new(V_REF);
18✔
5410
   vlog_set_ident(oref, p_identifier());
18✔
5411
   vlog_set_loc(oref, &state.last_loc);
18✔
5412

5413
   vlog_add_port(udp, oref);
18✔
5414

5415
   consume(tCOMMA);
18✔
5416

5417
   vlog_node_t iref = vlog_new(V_REF);
18✔
5418
   vlog_set_ident(iref, p_identifier());
18✔
5419
   vlog_set_loc(iref, &state.last_loc);
18✔
5420

5421
   vlog_add_port(udp, iref);
18✔
5422

5423
   while (optional(tCOMMA)) {
42✔
5424
      vlog_node_t iref = vlog_new(V_REF);
24✔
5425
      vlog_set_ident(iref, p_identifier());
24✔
5426
      vlog_set_loc(iref, &state.last_loc);
24✔
5427

5428
      vlog_add_port(udp, iref);
24✔
5429
   }
5430
}
18✔
5431

5432
static vlog_node_t p_udp_nonansi_declaration(void)
18✔
5433
{
5434
   // { attribute_instance } primitive udp_identifier ( udp_port_list ) ;
5435

5436
   BEGIN("UDP non-ANSI declaration");
18✔
5437

5438
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
18✔
5439

5440
   consume(tPRIMITIVE);
18✔
5441

5442
   ident_t id, ext;
18✔
5443
   p_external_identifier(&id, &ext);
18✔
5444
   vlog_set_ident2(udp, id);
18✔
5445

5446
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
18✔
5447
   vlog_set_ident(udp, qual);
18✔
5448

5449
   consume(tLPAREN);
18✔
5450

5451
   p_udp_port_list(udp);
18✔
5452

5453
   consume(tRPAREN);
18✔
5454
   consume(tSEMI);
18✔
5455

5456
   vlog_set_loc(udp, CURRENT_LOC);
18✔
5457
   return udp;
18✔
5458
}
5459

5460
static void p_list_of_udp_port_identifiers(vlog_node_t udp, v_port_kind_t kind)
19✔
5461
{
5462
   // port_identifier { , port_identifier }
5463

5464
   BEGIN("list of UDP port identifiers");
38✔
5465

5466
   do {
42✔
5467
      ident_t id, ext;
42✔
5468
      p_external_identifier(&id, &ext);
42✔
5469

5470
      vlog_node_t p = vlog_new(V_PORT_DECL);
42✔
5471
      vlog_set_subkind(p, kind);
42✔
5472
      vlog_set_ident(p, id);
42✔
5473
      vlog_set_ident2(p, ext);
42✔
5474
      vlog_set_type(p, logic_type());
42✔
5475
      vlog_set_loc(p, &state.last_loc);
42✔
5476

5477
      vlog_add_decl(udp, p);
42✔
5478
      vlog_symtab_put(symtab, p);
42✔
5479
   } while (optional(tCOMMA));
42✔
5480
}
19✔
5481

5482
static void p_udp_output_declaration(vlog_node_t udp, bool *has_reg)
19✔
5483
{
5484
   // { attribute_instance } output port_identifier
5485
   //    | { attribute_instance } output reg port_identifier
5486
   //         [ = constant_expression ]
5487

5488
   BEGIN("UDP output declaration");
38✔
5489

5490
   consume(tOUTPUT);
19✔
5491

5492
   const bool isreg = optional(tREG);
19✔
5493

5494
   ident_t id, ext;
19✔
5495
   p_external_identifier(&id, &ext);
19✔
5496

5497
   vlog_node_t logic = logic_type();
19✔
5498

5499
   vlog_node_t v = vlog_new(V_PORT_DECL);
19✔
5500
   vlog_set_subkind(v, V_PORT_OUTPUT);
19✔
5501
   vlog_set_ident(v, id);
19✔
5502
   vlog_set_ident2(v, ext);
19✔
5503
   vlog_set_type(v, logic);
19✔
5504
   vlog_set_loc(v, &state.last_loc);
19✔
5505

5506
   vlog_add_decl(udp, v);
19✔
5507
   vlog_symtab_put(symtab, v);
19✔
5508

5509
   if (isreg) {
19✔
5510
      vlog_node_t reg = vlog_new(V_VAR_DECL);
2✔
5511
      vlog_set_loc(reg, &state.last_loc);
2✔
5512
      vlog_set_ident(reg, id);
2✔
5513
      vlog_set_type(reg, logic);
2✔
5514

5515
      vlog_add_decl(udp, reg);
2✔
5516
      vlog_symtab_put(symtab, reg);
2✔
5517

5518
      *has_reg = true;
2✔
5519
   }
5520
}
19✔
5521

5522
static void p_udp_input_declaration(vlog_node_t udp)
19✔
5523
{
5524
   // { attribute_instance } input list_of_udp_port_identifiers
5525

5526
   BEGIN("UDP input declaration");
38✔
5527

5528
   consume(tINPUT);
19✔
5529

5530
   p_list_of_udp_port_identifiers(udp, V_PORT_INPUT);
19✔
5531
}
19✔
5532

5533
static vlog_node_t p_udp_reg_declaration(void)
9✔
5534
{
5535
   // { attribute_instance } reg variable_identifier
5536

5537
   BEGIN("UDP reg declaration");
9✔
5538

5539
   consume(tREG);
9✔
5540

5541
   ident_t id = p_identifier();
9✔
5542

5543
   vlog_node_t reg = vlog_new(V_VAR_DECL);
9✔
5544
   vlog_set_loc(reg, &state.last_loc);
9✔
5545
   vlog_set_ident(reg, id);
9✔
5546
   vlog_set_type(reg, logic_type());
9✔
5547

5548
   return reg;
9✔
5549
}
5550

5551
static void p_udp_port_declaration(vlog_node_t udp, bool *has_reg)
45✔
5552
{
5553
   // udp_output_declaration ; | udp_input_declaration ; | udp_reg_declaration ;
5554

5555
   BEGIN("UDP port declaration");
90✔
5556

5557
   switch (peek()) {
45✔
5558
   case tOUTPUT:
18✔
5559
      p_udp_output_declaration(udp, has_reg);
18✔
5560
      break;
18✔
5561
   case tINPUT:
18✔
5562
      p_udp_input_declaration(udp);
18✔
5563
      break;
18✔
5564
   case tREG:
9✔
5565
      {
5566
         vlog_node_t v = p_udp_reg_declaration();
9✔
5567
         vlog_add_decl(udp, v);
9✔
5568
         vlog_symtab_put(symtab, v);
9✔
5569
         *has_reg = true;
9✔
5570
      }
5571
      break;
9✔
5572
   default:
×
5573
      one_of(tOUTPUT, tINPUT, tREG);
×
5574
      break;
×
5575
   }
5576

5577
   consume(tSEMI);
45✔
5578
}
45✔
5579

5580
static void p_udp_declaration_port_list(vlog_node_t udp, bool *has_reg)
1✔
5581
{
5582
   // udp_output_declaration , udp_input_declaration { , udp_input_declaration }
5583

5584
   BEGIN("UDP declaration port list");
2✔
5585

5586
   p_udp_output_declaration(udp, has_reg);
1✔
5587

5588
   consume(tCOMMA);
1✔
5589

5590
   do {
1✔
5591
      p_udp_input_declaration(udp);
1✔
5592
   } while (optional(tCOMMA));
1✔
5593

5594
   const int ndecls = vlog_decls(udp);
1✔
5595
   for (int i = 0; i < ndecls; i++) {
4✔
5596
      vlog_node_t p = vlog_decl(udp, i);
3✔
5597
      if (vlog_kind(p) != V_PORT_DECL)
3✔
5598
         continue;
1✔
5599

5600
      vlog_node_t ref = vlog_new(V_REF);
2✔
5601
      vlog_set_loc(ref, vlog_loc(p));
2✔
5602
      vlog_set_ident(ref, vlog_ident(p));
2✔
5603
      vlog_set_ref(ref, p);
2✔
5604

5605
      vlog_add_port(udp, ref);
2✔
5606
   }
5607
}
1✔
5608

5609
static vlog_node_t p_output_symbol(void)
85✔
5610
{
5611
   // 0 | 1 | x | X
5612

5613
   BEGIN("output symbol");
85✔
5614

5615
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
85✔
5616
   vlog_set_subkind(v, V_UDP_SYMBOL_OUTPUT);
85✔
5617

5618
   if (consume(tUDPLEVEL)) {
85✔
5619
      switch (state.last_lval.i64) {
85✔
5620
      case '0':
85✔
5621
      case '1':
5622
      case 'x':
5623
      case 'X':
5624
         vlog_set_ival(v, state.last_lval.i64);
85✔
5625
         break;
85✔
5626
      default:
×
5627
         parse_error(&state.last_loc, "'%c' is not a valid output symbol",
×
5628
                  (char)state.last_lval.i64);
5629
         break;
5630
      }
5631
   }
5632

5633
   vlog_set_loc(v, CURRENT_LOC);
85✔
5634
   return v;
85✔
5635
}
5636

5637
static vlog_node_t p_level_symbol(void)
393✔
5638
{
5639
   // 0 | 1 | x | X | ? | b | B
5640

5641
   BEGIN("level symbol");
393✔
5642

5643
   consume(tUDPLEVEL);
393✔
5644

5645
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
393✔
5646
   vlog_set_subkind(v, V_UDP_SYMBOL_INPUT);
393✔
5647
   vlog_set_ival(v, state.last_lval.i64);
393✔
5648

5649
   vlog_set_loc(v, CURRENT_LOC);
393✔
5650
   return v;
393✔
5651
}
5652

5653
static vlog_node_t p_next_state(void)
85✔
5654
{
5655
   // output_symbol | -
5656

5657
   BEGIN("next state");
170✔
5658

5659
   switch (peek()) {
85✔
5660
   case tMINUS:
27✔
5661
      consume(tMINUS);
27✔
5662
      break;
27✔
5663
   case tUDPLEVEL:
58✔
5664
      return p_output_symbol();
58✔
5665
   default:
×
5666
      one_of(tUDPLEVEL, tMINUS);
×
5667
   }
5668

5669
   vlog_node_t v = vlog_new(V_UDP_LEVEL);
27✔
5670
   vlog_set_subkind(v, V_UDP_SYMBOL_OUTPUT);
27✔
5671
   vlog_set_ival(v, '-');
27✔
5672

5673
   vlog_set_loc(v, CURRENT_LOC);
27✔
5674
   return v;
27✔
5675
}
5676

5677
static vlog_node_t p_edge_symbol(void)
12✔
5678
{
5679
   // r | R | f | F | p | P | n | N | *
5680

5681
   BEGIN("edge symbol");
12✔
5682

5683
   consume(tUDPEDGE);
12✔
5684

5685
   char left, right;
12✔
5686
   switch (state.last_lval.i64) {
12✔
5687
   case 'r': case 'R': left = '0'; right = '1'; break;
3✔
5688
   case 'f': case 'F': left = '1'; right = '0'; break;
×
5689
   case 'p': case 'P': left = 'p'; right = 'p'; break;
×
5690
   case 'n': case 'N': left = 'n'; right = 'N'; break;
×
5691
   case '*':           left = '?'; right = '?'; break;
9✔
5692
   }
5693

5694
   vlog_node_t lsym = vlog_new(V_UDP_LEVEL);
12✔
5695
   vlog_set_ival(lsym, left);
12✔
5696

5697
   vlog_node_t rsym = vlog_new(V_UDP_LEVEL);
12✔
5698
   vlog_set_ival(rsym, right);
12✔
5699

5700
   vlog_node_t v = vlog_new(V_UDP_EDGE);
12✔
5701
   vlog_set_subkind(v, V_UDP_SYMBOL_INPUT);
12✔
5702
   vlog_set_left(v, lsym);
12✔
5703
   vlog_set_right(v, rsym);
12✔
5704

5705
   vlog_set_loc(v, CURRENT_LOC);
12✔
5706
   return v;
12✔
5707
}
5708

5709
static void p_level_input_list(vlog_node_t entry)
27✔
5710
{
5711
   // level_symbol { level_symbol }
5712

5713
   BEGIN("level input list");
54✔
5714

5715
   do {
78✔
5716
      vlog_add_param(entry, p_level_symbol());
78✔
5717
   } while (not_at_token(tCOLON));
78✔
5718
}
27✔
5719

5720
static vlog_node_t p_edge_indicator(void)
85✔
5721
{
5722
   // ( level_symbol level_symbol ) | edge_symbol
5723

5724
   BEGIN("edge indicator");
170✔
5725

5726
   switch (peek()) {
85✔
5727
   case tUDPEDGE:
12✔
5728
      return p_edge_symbol();
12✔
5729
   case tLPAREN:
73✔
5730
      {
5731
         consume(tLPAREN);
73✔
5732

5733
         vlog_node_t v = vlog_new(V_UDP_EDGE);
73✔
5734
         vlog_set_left(v, p_level_symbol());
73✔
5735
         vlog_set_right(v, p_level_symbol());
73✔
5736

5737
         consume(tRPAREN);
73✔
5738

5739
         vlog_set_loc(v, CURRENT_LOC);
73✔
5740
         return v;
73✔
5741
      }
5742
      break;
×
5743
   default:
×
5744
      should_not_reach_here();
5745
   }
5746
}
5747

5748
static void p_seq_input_list(vlog_node_t entry)
85✔
5749
{
5750
   // level_input_list | edge_input_list
5751

5752
   BEGIN("sequential input list");
170✔
5753

5754
   bool have_edge = false;
85✔
5755
   do {
169✔
5756
      switch (peek()) {
169✔
5757
      case tUDPEDGE:
85✔
5758
      case tLPAREN:
5759
         vlog_add_param(entry, p_edge_indicator());
85✔
5760
         if (have_edge)
85✔
5761
            parse_error(&state.last_loc, "a sequential input list may have at "
1✔
5762
                        "most one edge indicator");
5763
         have_edge = true;
5764
         break;
5765

5766
      case tUDPLEVEL:
84✔
5767
         vlog_add_param(entry, p_level_symbol());
84✔
5768
         break;
84✔
5769

5770
      default:
×
5771
         one_of(tUDPEDGE, tUDPIND, tUDPLEVEL);
×
5772
         break;
×
5773
      }
5774
   } while (not_at_token(tCOLON));
169✔
5775
}
85✔
5776

5777
static vlog_node_t p_combinational_entry(void)
27✔
5778
{
5779
   // level_input_list : output_symbol ;
5780

5781
   BEGIN("combinational entry");
27✔
5782

5783
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
27✔
5784
   p_level_input_list(v);
27✔
5785

5786
   consume(tCOLON);
27✔
5787

5788
   vlog_add_param(v, p_output_symbol());
27✔
5789

5790
   consume(tSEMI);
27✔
5791

5792
   vlog_set_loc(v, CURRENT_LOC);
27✔
5793
   return v;
27✔
5794
}
5795

5796
static vlog_node_t p_combinational_body(void)
8✔
5797
{
5798
   // table combinational_entry { combinational_entry } endtable
5799

5800
   BEGIN("combinational UDP body");
8✔
5801

5802
   consume(tTABLE);
8✔
5803

5804
   scan_as_udp();
8✔
5805

5806
   vlog_node_t v = vlog_new(V_UDP_TABLE);
8✔
5807
   vlog_set_subkind(v, V_UDP_COMB);
8✔
5808
   vlog_set_ident(v, ident_new("combinational"));
8✔
5809

5810
   do {
27✔
5811
      vlog_add_param(v, p_combinational_entry());
27✔
5812
   } while (not_at_token(tENDTABLE));
27✔
5813

5814
   scan_as_verilog();
8✔
5815

5816
   consume(tENDTABLE);
8✔
5817

5818
   vlog_set_loc(v, CURRENT_LOC);
8✔
5819
   return v;
8✔
5820
}
5821

5822
static vlog_node_t p_sequential_entry(void)
85✔
5823
{
5824
   // seq_input_list : current_state : next_state ;
5825

5826
   BEGIN("sequential entry");
85✔
5827

5828
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
85✔
5829
   p_seq_input_list(v);
85✔
5830

5831
   consume(tCOLON);
85✔
5832

5833
   vlog_add_param(v, p_level_symbol());
85✔
5834

5835
   consume(tCOLON);
85✔
5836

5837
   vlog_add_param(v, p_next_state());
85✔
5838

5839
   consume(tSEMI);
85✔
5840

5841
   vlog_set_loc(v, CURRENT_LOC);
85✔
5842
   return v;
85✔
5843
}
5844

5845
static vlog_node_t p_udp_initial_statement(void)
5✔
5846
{
5847
   // initial output_port_identifier = init_val ;
5848

5849
   BEGIN("UDP initial statement");
5✔
5850

5851
   consume(tINITIAL);
5✔
5852

5853
   vlog_node_t ref = vlog_new(V_REF);
5✔
5854
   vlog_set_ident(ref, p_identifier());
5✔
5855
   vlog_set_loc(ref, &state.last_loc);
5✔
5856

5857
   vlog_symtab_lookup(symtab, ref);
5✔
5858

5859
   consume(tEQ);
5✔
5860

5861
   vlog_node_t v = vlog_new(V_BASSIGN);
5✔
5862
   vlog_set_target(v, ref);
5✔
5863
   vlog_set_value(v, p_integral_number());
5✔
5864

5865
   consume(tSEMI);
5✔
5866

5867
   vlog_set_loc(v, CURRENT_LOC);
5✔
5868
   return v;
5✔
5869
}
5870

5871
static vlog_node_t p_sequential_body(void)
11✔
5872
{
5873
   // [ udp_initial_statement ] table sequential_entry
5874
   //     { sequential_entry } endtable
5875

5876
   BEGIN("sequential UDP body");
11✔
5877

5878
   vlog_node_t v = vlog_new(V_UDP_TABLE);
11✔
5879
   vlog_set_subkind(v, V_UDP_SEQ);
11✔
5880
   vlog_set_ident(v, ident_new("sequential"));
11✔
5881

5882
   if (peek() == tINITIAL)
11✔
5883
      vlog_add_stmt(v, p_udp_initial_statement());
5✔
5884

5885
   consume(tTABLE);
11✔
5886

5887
   scan_as_udp();
11✔
5888

5889
   do {
85✔
5890
      vlog_add_param(v, p_sequential_entry());
85✔
5891
   } while (not_at_token(tENDTABLE));
85✔
5892

5893
   scan_as_verilog();
11✔
5894

5895
   consume(tENDTABLE);
11✔
5896

5897
   vlog_set_loc(v, CURRENT_LOC);
11✔
5898
   return v;
11✔
5899
}
5900

5901
static vlog_node_t p_udp_body(bool has_reg)
19✔
5902
{
5903
   // combinational_body | sequential_body
5904

5905
   BEGIN("UDP body");
38✔
5906

5907
   if (has_reg)
19✔
5908
      return p_sequential_body();
11✔
5909
   else
5910
      return p_combinational_body();
8✔
5911
}
5912

5913
static vlog_node_t p_udp_ansi_declaration(bool *has_reg)
1✔
5914
{
5915
   // { attribute_instance } primitive udp_identifier
5916
   //    ( udp_declaration_port_list ) ;
5917

5918
   BEGIN("UDP ANSI declaration");
1✔
5919

5920
   optional_attributes();
1✔
5921

5922
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
1✔
5923

5924
   consume(tPRIMITIVE);
1✔
5925

5926
   ident_t id, ext;
1✔
5927
   p_external_identifier(&id, &ext);
1✔
5928
   vlog_set_ident2(udp, id);
1✔
5929

5930
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
1✔
5931
   vlog_set_ident(udp, qual);
1✔
5932

5933
   vlog_symtab_push(symtab, udp);
1✔
5934

5935
   consume(tLPAREN);
1✔
5936

5937
   p_udp_declaration_port_list(udp, has_reg);
1✔
5938

5939
   consume(tRPAREN);
1✔
5940
   consume(tSEMI);
1✔
5941

5942
   vlog_set_loc(udp, CURRENT_LOC);
1✔
5943
   return udp;
1✔
5944
}
5945

5946
static vlog_node_t p_udp_declaration(void)
19✔
5947
{
5948
   // udp_nonansi_declaration udp_port_declaration { udp_port_declaration }
5949
   //        udp_body endprimitive [ : udp_identifier ]
5950
   //   | udp_ansi_declaration udp_body endprimitive [ : udp_identifier ]
5951
   //   | extern udp_nonansi_declaration
5952
   //   | extern udp_ansi_declaration
5953
   //   | { attribute_instance } primitive udp_identifier ( .* ) ;
5954
   //        { udp_port_declaration } udp_body endprimitive [ : udp_identifier ]
5955

5956
   BEGIN("UDP declaration");
19✔
5957

5958
   bool has_reg = false;
19✔
5959
   vlog_node_t udp;
19✔
5960
   if (peek_nth(4) == tID) {
19✔
5961
      udp = p_udp_nonansi_declaration();
18✔
5962

5963
      vlog_symtab_push(symtab, udp);
18✔
5964

5965
      do {
45✔
5966
         p_udp_port_declaration(udp, &has_reg);
45✔
5967
      } while (not_at_token(tTABLE, tINITIAL));
45✔
5968

5969
      const int nports = vlog_ports(udp);
18✔
5970
      for (int i = 0; i < nports; i++)
78✔
5971
         vlog_symtab_lookup(symtab, vlog_port(udp, i));
60✔
5972
   }
5973
   else
5974
      udp = p_udp_ansi_declaration(&has_reg);
1✔
5975

5976
   vlog_add_stmt(udp, p_udp_body(has_reg));
19✔
5977

5978
   vlog_symtab_pop(symtab);
19✔
5979

5980
   consume(tENDPRIMITIVE);
19✔
5981

5982
   return udp;
19✔
5983
}
5984

5985
static vlog_node_t p_description(void)
242✔
5986
{
5987
   // module_declaration | udp_declaration | interface_declaration
5988
   //   | program_declaration | package_declaration
5989
   //   | { attribute_instance } package_item
5990
   //   | { attribute_instance } bind_directive
5991
   //   | config_declaration
5992

5993
   BEGIN("description");
484✔
5994

5995
   skip_over_attributes();
242✔
5996

5997
   switch (peek()) {
242✔
5998
   case tMODULE:
223✔
5999
      return p_module_declaration();
223✔
6000
   case tPRIMITIVE:
19✔
6001
      return p_udp_declaration();
19✔
6002
   default:
×
6003
      expect(tPRIMITIVE, tMODULE);
×
6004
      return NULL;
×
6005
   }
6006
}
6007

6008
static void p_timescale_compiler_directive(void)
11✔
6009
{
6010
   // `timescale time_unit / time_precision
6011

6012
   BEGIN("timescale compiler directive");
22✔
6013

6014
   consume(tTIMESCALE);
11✔
6015

6016
   consume(tUNSIGNED);
11✔
6017
   char *unit_value LOCAL = state.last_lval.str;
22✔
6018

6019
   consume(tID);
11✔
6020
   char *unit_name LOCAL = state.last_lval.str;
22✔
6021

6022
   consume(tOVER);
11✔
6023

6024
   consume(tUNSIGNED);
11✔
6025
   char *prec_value LOCAL = state.last_lval.str;
22✔
6026

6027
   consume(tID);
11✔
6028
   char *prec_name LOCAL = state.last_lval.str;
22✔
6029

6030
   set_timescale(unit_value, unit_name, prec_value, prec_name, CURRENT_LOC);
11✔
6031
}
11✔
6032

6033
static void p_defaultnettype_compiler_directive(void)
12✔
6034
{
6035
   // `default_nettype wire | tri | tri0 | tri1 | wand | triand | wor
6036
   //    | trior | trireg | uwire | none
6037

6038
   BEGIN("default_nettype directive");
24✔
6039

6040
   consume(tDEFNETTYPE);
12✔
6041

6042
   switch (one_of(tWIRE, tTRI, tTRI0, tTRI1, tWAND, tTRIAND, tWOR, tTRIOR,
12✔
6043
                  tTRIREG, tUWIRE, tNONE)) {
6044
   case tWIRE: implicit_kind = V_NET_WIRE; break;
1✔
6045
   case tNONE: implicit_kind = V_NET_NONE; break;
1✔
6046
   }
6047
}
12✔
6048

6049
static void p_keywords_directive(void)
1✔
6050
{
6051
   // `begin_keywords "version_specifier"
6052

6053
   BEGIN("keywords directive");
1✔
6054

6055
   consume(tBEGINKEYWORDS);
1✔
6056

6057
   consume(tSTRING);
1✔
6058
   free(state.last_lval.str);
1✔
6059
}
1✔
6060

6061
static void p_endkeywords_directive(void)
1✔
6062
{
6063
   // `end_keywords
6064

6065
   BEGIN("endkeywords directive");
2✔
6066

6067
   consume(tENDKEYWORDS);
1✔
6068
}
1✔
6069

6070
static void p_resetall_directive(void)
1✔
6071
{
6072
   // `resetall
6073

6074
   BEGIN("resetall directive");
1✔
6075

6076
   consume(tRESETALL);
1✔
6077

6078
   implicit_kind = V_NET_WIRE;
1✔
6079
}
1✔
6080

6081
static void p_directive_list(void)
243✔
6082
{
6083
   BEGIN("directive list");
243✔
6084

6085
   for (;;) {
269✔
6086
      switch (peek()) {
269✔
6087
      case tDEFNETTYPE:
12✔
6088
         p_defaultnettype_compiler_directive();
12✔
6089
         break;
12✔
6090
      case tTIMESCALE:
11✔
6091
         p_timescale_compiler_directive();
11✔
6092
         break;
11✔
6093
      case tBEGINKEYWORDS:
1✔
6094
         p_keywords_directive();
1✔
6095
         break;
1✔
6096
      case tENDKEYWORDS:
1✔
6097
         p_endkeywords_directive();
1✔
6098
         break;
1✔
6099
      case tRESETALL:
1✔
6100
         p_resetall_directive();
1✔
6101
         break;
1✔
6102
      default:
6103
         return;
243✔
6104
      }
6105
   }
6106
}
6107

6108
static vlog_node_t end_of_file(void)
192✔
6109
{
6110
   vlog_symtab_pop(symtab);
192✔
6111
   vlog_symtab_free(symtab);
192✔
6112
   symtab = NULL;
192✔
6113
   return NULL;
192✔
6114
}
6115

6116
vlog_node_t vlog_parse(void)
434✔
6117
{
6118
   state.n_correct = RECOVER_THRESH;
434✔
6119
   param_kind = V_PARAM_DECL;
434✔
6120

6121
   scan_as_verilog();
434✔
6122

6123
   if (symtab == NULL) {
434✔
6124
      symtab = vlog_symtab_new();
193✔
6125
      vlog_symtab_push(symtab, NULL);   // Compilation unit scope
193✔
6126
      vlog_symtab_poison(symtab, error_marker());
193✔
6127
   }
6128

6129
   if (peek() == tEOF)
434✔
6130
      return end_of_file();
191✔
6131

6132
   p_directive_list();
243✔
6133

6134
   make_new_arena();
243✔
6135

6136
   if (peek() == tEOF)
243✔
6137
      return end_of_file();
1✔
6138

6139
   return p_description();
242✔
6140
}
6141

6142
void reset_verilog_parser(void)
371✔
6143
{
6144
   state.tokenq_head = state.tokenq_tail = 0;
371✔
6145
   implicit_kind = V_NET_WIRE;
371✔
6146
   last_attr = NULL;
371✔
6147

6148
   if (symtab != NULL) {
371✔
6149
      vlog_symtab_free(symtab);
×
6150
      symtab = NULL;
×
6151
   }
6152
}
371✔
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