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

nickg / nvc / 14250539893

03 Apr 2025 06:50PM UTC coverage: 92.315% (+0.001%) from 92.314%
14250539893

push

github

web-flow
Parse System Verilog always blocks. (#1181)

9 of 11 new or added lines in 2 files covered. (81.82%)

2 existing lines in 1 file now uncovered.

68754 of 74478 relevant lines covered (92.31%)

422608.62 hits per line

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

95.46
/src/vlog/vlog-parse.c
1
//
2
//  Copyright (C) 2024  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

27
#include <ctype.h>
28
#include <string.h>
29
#include <stdlib.h>
30
#include <assert.h>
31

32
#define RECOVER_THRESH 5
33
#define TRACE_PARSE    0
34
#define TRACE_RECOVERY 0
35
#define TOKENQ_SIZE    8
36

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

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

59
typedef struct {
60
   const char *old_hint;
61
   loc_t       old_start_loc;
62
} rule_state_t;
63

64
static parse_state_t state;
65

66
extern loc_t yylloc;
67

68
#define scan(...) _scan(1, __VA_ARGS__, -1)
69
#define expect(...) _expect(1, __VA_ARGS__, -1)
70
#define one_of(...) _one_of(1, __VA_ARGS__, -1)
71
#define not_at_token(...) ((peek() != tEOF) && !_scan(1, __VA_ARGS__, -1))
72
#define peek() peek_nth(1)
73

74
#define parse_error(loc, ...) do {              \
75
      if (state.n_correct >= RECOVER_THRESH)    \
76
         error_at((loc), __VA_ARGS__);          \
77
   } while (0)
78

79
#if TRACE_PARSE
80
static void _push_state(const rule_state_t *s);
81
#else
82
#define _push_state(s)
83
#endif
84

85
#define EXTEND(s)                                                      \
86
   __attribute__((cleanup(_pop_state), unused))                        \
87
   const rule_state_t _state = { state.hint_str, state.start_loc };    \
88
   state.hint_str = s;                                                 \
89
   _push_state(&_state);
90

91
#define BEGIN_WITH_HEAD(s, t)                            \
92
   EXTEND(s);                                            \
93
   state.start_loc = (t) ? *vlog_loc(t) : LOC_INVALID;   \
94

95
#define BEGIN(s)  BEGIN_WITH_HEAD(s, NULL)
96

97
#define CURRENT_LOC _diff_loc(&state.start_loc, &state.last_loc)
98

99
static vlog_node_t p_statement_or_null(void);
100
static vlog_node_t p_expression(void);
101
static vlog_node_t p_constant_expression(void);
102
static vlog_node_t p_data_type(void);
103
static void p_list_of_variable_decl_assignments(vlog_node_t parent,
104
                                                vlog_node_t datatype);
105
static vlog_node_t p_variable_lvalue(void);
106
static vlog_node_t p_bit_select(ident_t id);
107

108
static inline void _pop_state(const rule_state_t *r)
22,772✔
109
{
110
#if TRACE_PARSE
111
   printf("%*s<-- %s\n", state.depth--, "", state.hint_str);
112
#endif
113

114
   state.hint_str = r->old_hint;
22,772✔
115

116
   if (r->old_start_loc.first_line != LINE_INVALID)
22,772✔
117
      state.start_loc = r->old_start_loc;
8,620✔
118
}
22,772✔
119

120
#if TRACE_PARSE
121
static inline void _push_state(const rule_state_t *r)
122
{
123
   printf("%*s--> %s\n", state.depth++, "", state.hint_str);
124
}
125
#endif
126

127
static token_t peek_nth(int n)
36,317✔
128
{
129
   while (((state.tokenq_head - state.tokenq_tail) & (TOKENQ_SIZE - 1)) < n) {
46,296✔
130
      const token_t token = processed_yylex();
9,979✔
131

132
      int next = (state.tokenq_head + 1) & (TOKENQ_SIZE - 1);
9,979✔
133
      assert(next != state.tokenq_tail);
9,979✔
134

135
      extern yylval_t yylval;
9,979✔
136

137
      state.tokenq[state.tokenq_head].token = token;
9,979✔
138
      state.tokenq[state.tokenq_head].lval  = yylval;
9,979✔
139
      state.tokenq[state.tokenq_head].loc   = yylloc;
9,979✔
140

141
      state.tokenq_head = next;
9,979✔
142
   }
143

144
   const int pos = (state.tokenq_tail + n - 1) & (TOKENQ_SIZE - 1);
36,317✔
145
   return state.tokenq[pos].token;
36,317✔
146
}
147

148
static void drop_token(void)
9,882✔
149
{
150
   assert(state.tokenq_head != state.tokenq_tail);
9,882✔
151

152
   if (state.start_loc.first_line == LINE_INVALID)
9,882✔
153
      state.start_loc = state.tokenq[state.tokenq_tail].loc;
5,353✔
154

155
   state.last_lval = state.tokenq[state.tokenq_tail].lval;
9,882✔
156
   state.last_loc  = state.tokenq[state.tokenq_tail].loc;
9,882✔
157

158
   state.tokenq_tail = (state.tokenq_tail + 1) & (TOKENQ_SIZE - 1);
9,882✔
159

160
   state.nopt_hist = 0;
9,882✔
161
}
9,882✔
162

163
static void drop_tokens_until(token_t tok)
2✔
164
{
165
   token_t next = tEOF;
2✔
166
   do {
7✔
167
      free_token(tok, &state.last_lval);
7✔
168
      next = peek();
7✔
169
      drop_token();
7✔
170
   } while ((tok != next) && (next != tEOF));
7✔
171

172
#if TRACE_RECOVERY
173
   if (peek() != tEOF)
174
      fmt_loc(stdout, &(tokenq[tokenq_tail].loc));
175
#endif
176
}
2✔
177

178
static void _vexpect(va_list ap)
8✔
179
{
180
   if (state.n_correct >= RECOVER_THRESH) {
8✔
181
      diag_t *d = diag_new(DIAG_ERROR, &(state.tokenq[state.tokenq_tail].loc));
3✔
182
      diag_printf(d, "unexpected $yellow$%s$$ while parsing %s, expecting ",
3✔
183
                  token_str(peek()), state.hint_str);
184

185
      bool first = true;
3✔
186
      for (int i = 0; i < state.nopt_hist; i++) {
3✔
187
         diag_printf(d, "%s$yellow$%s$$", i == 0 ? "one of " : ", ",
×
188
                     token_str(state.opt_hist[i]));
189
         first = false;
×
190
      }
191

192
      int tok = va_arg(ap, int);
3✔
193
      while (tok != -1) {
31✔
194
         const int tmp = tok;
28✔
195
         tok = va_arg(ap, int);
28✔
196

197
         if (first && (tok != -1))
28✔
198
            diag_printf(d, "one of ");
2✔
199
         else if (!first)
26✔
200
            diag_printf(d, (tok == -1) ? " or " : ", ");
48✔
201

202
         diag_printf(d, "$yellow$%s$$", token_str(tmp));
28✔
203

204
         first = false;
28✔
205
      }
206

207
      diag_hint(d, &(state.tokenq[state.tokenq_tail].loc),
3✔
208
                "this token was unexpected");
209
      diag_emit(d);
3✔
210
   }
211

212
   state.n_correct = 0;
8✔
213

214
   drop_token();
8✔
215
}
8✔
216

217
static void _expect(int dummy, ...)
4✔
218
{
219
   va_list ap;
4✔
220
   va_start(ap, dummy);
4✔
221
   _vexpect(ap);
4✔
222
   va_end(ap);
4✔
223
}
4✔
224

225
static bool consume(token_t tok)
9,871✔
226
{
227
   const token_t got = peek();
9,871✔
228
   if (tok != got) {
9,871✔
229
      expect(tok);
4✔
230
      return false;
4✔
231
   }
232
   else {
233
      state.n_correct++;
9,867✔
234
      drop_token();
9,867✔
235
      return true;
9,867✔
236
   }
237
}
238

239
static bool optional(token_t tok)
4,256✔
240
{
241
   if (peek() == tok) {
4,256✔
242
      consume(tok);
1,066✔
243
      return true;
1,066✔
244
   }
245
   else {
246
      if (state.nopt_hist < ARRAY_LEN(state.opt_hist))
3,190✔
247
         state.opt_hist[state.nopt_hist++] = tok;
3,190✔
248
      return false;
3,190✔
249
   }
250
}
251

252
static bool _scan(int dummy, ...)
2,901✔
253
{
254
   va_list ap;
2,901✔
255
   va_start(ap, dummy);
2,901✔
256

257
   token_t p = peek();
2,901✔
258
   bool found = false;
2,901✔
259

260
   while (!found) {
2,901✔
261
      const int tok = va_arg(ap, token_t);
8,063✔
262
      if (tok == -1)
8,063✔
263
         break;
264
      else if (p == tok)
5,816✔
265
         found = true;
266
   }
267

268
   va_end(ap);
2,901✔
269
   return found;
2,901✔
270
}
271

272
static int _one_of(int dummy, ...)
649✔
273
{
274
   va_list ap;
649✔
275
   va_start(ap, dummy);
649✔
276

277
   token_t p = peek();
649✔
278
   bool found = false;
649✔
279

280
   while (!found) {
649✔
281
      const int tok = va_arg(ap, token_t);
2,499✔
282
      if (tok == -1)
2,499✔
283
         break;
284
      else if (p == tok)
2,495✔
285
         found = true;
286
   }
287

288
   va_end(ap);
649✔
289

290
   if (found) {
649✔
291
      consume(p);
645✔
292
      return p;
645✔
293
   }
294
   else {
295
      va_start(ap, dummy);
4✔
296
      _vexpect(ap);
4✔
297
      va_end(ap);
4✔
298

299
      return -1;
4✔
300
   }
301
}
302

303
static const loc_t *_diff_loc(const loc_t *start, const loc_t *end)
6,020✔
304
{
305
   static loc_t result;
6,020✔
306

307
   result = get_loc(start->first_line,
6,020✔
308
                    start->first_column,
6,020✔
309
                    end->first_line + end->line_delta,
6,020✔
310
                    end->first_column + end->column_delta,
6,020✔
311
                    start->file_ref);
6,020✔
312
   return &result;
6,020✔
313
}
314

315
static void set_timescale(const char *unit_value, const char *unit_name,
9✔
316
                          const char *prec_value, const char *prec_name,
317
                          const loc_t *loc)
318
{
319
   // See IEEE 1800-2017 section 22.7 for rules
320

321
   struct {
9✔
322
      const char *value;
323
      const char *name;
324
      int64_t     parsed;
325
   } args[] = {
9✔
326
      { unit_value, unit_name },
327
      { prec_value, prec_name },
328
   };
329

330
   for (int i = 0; i < ARRAY_LEN(args); i++) {
27✔
331
      static const struct {
332
         const char *name;
333
         int64_t value;
334
      } valid_units[] = {
335
         { "s", INT64_C(60000000000000) },
336
         { "ms", 1000000000000 },
337
         { "us", 1000000000 },
338
         { "ns", 1000000 },
339
         { "ps", 1000 },
340
         { "fs", 1 },
341
      };
342

343
      bool name_valid = false;
85✔
344
      for (int j = 0; j < ARRAY_LEN(valid_units); j++) {
85✔
345
         if (strcmp(valid_units[j].name, args[i].name) == 0) {
84✔
346
            args[i].parsed = valid_units[j].value;
17✔
347
            name_valid = true;
17✔
348
            break;
17✔
349
         }
350
      }
351

352
      if (!name_valid)
17✔
353
         error_at(loc, "invalid time unit name '%s'", args[i].name);
1✔
354

355
      const int scale = atoi(args[i].value);
18✔
356
      if (scale != 1 && scale != 10 && scale != 100) {
18✔
357
         diag_t *d = diag_new(DIAG_ERROR, loc);
1✔
358
         diag_printf(d, "invalid order of magnitude in `timescale directive");
1✔
359
         diag_hint(d, NULL, "the valid values are 1, 10, and 100");
1✔
360
         diag_emit(d);
1✔
361
      }
362

363
      args[i].parsed *= scale;
18✔
364
   }
365

366
   // TODO: do something with parsed scale/precision
367
}
9✔
368

369
static ident_t error_marker(void)
2✔
370
{
371
   return well_known(W_ERROR);
2✔
372
}
373

374
static vlog_node_t dummy_expression(void)
×
375
{
376
   vlog_node_t v = vlog_new(V_NUMBER);
×
377
   vlog_set_number(v, number_new("1'b0"));
×
378
   return v;
×
379
}
380

381
static vlog_node_t logic_type(void)
79✔
382
{
383
   vlog_node_t v = vlog_new(V_DATA_TYPE);
79✔
384
   vlog_set_subkind(v, DT_LOGIC);
79✔
385
   return v;
79✔
386
}
387

388
static ident_t p_identifier(void)
1,510✔
389
{
390
   if (consume(tID)) {
1,510✔
391
      ident_t id = ident_new(state.last_lval.str);
1,509✔
392
      free(state.last_lval.str);
1,509✔
393
      return id;
1,509✔
394
   }
395
   else
396
      return error_marker();
1✔
397
}
398

399
static void p_external_identifier(ident_t *id, ident_t *ext)
302✔
400
{
401
   if (consume(tID)) {
302✔
402
      *id = ident_new(state.last_lval.str);
302✔
403
      for (char *p = state.last_lval.str; *p; p++)
1,427✔
404
         *p = toupper_iso88591(*p);
1,125✔
405
      *ext = ident_new(state.last_lval.str);
302✔
406
      free(state.last_lval.str);
302✔
407
   }
408
   else
409
      *id = *ext = error_marker();
×
410
}
302✔
411

412
static ident_t p_system_tf_identifier(void)
430✔
413
{
414
   if (consume(tSYSTASK)) {
430✔
415
      ident_t id = ident_new(state.last_lval.str);
430✔
416
      free(state.last_lval.str);
430✔
417
      return id;
430✔
418
   }
419
   else
420
      return error_marker();
×
421
}
422

423
static void p_attr_spec(void)
6✔
424
{
425
   // attr_name [ = constant_expression ]
426

427
   BEGIN("attribute specification");
12✔
428

429
   (void)p_identifier();
6✔
430

431
   if (optional(tEQ))
6✔
432
      (void)p_constant_expression();
×
433
}
6✔
434

435
static void p_attribute_instance(void)
6✔
436
{
437
   // (* attr_spec { , attr_spec } *)
438

439
   BEGIN("attribute instance");
12✔
440

441
   consume(tATTRBEGIN);
6✔
442

443
   do {
6✔
444
      p_attr_spec();
6✔
445
   } while (optional(tCOMMA));
6✔
446

447
   consume(tATTREND);
6✔
448
}
6✔
449

450
static vlog_node_t p_unsigned_number(void)
702✔
451
{
452
   // decimal_digit { _ | decimal_digit }
453

454
   BEGIN("unsigned number");
702✔
455

456
   consume(tUNSIGNED);
702✔
457

458
   vlog_node_t v = vlog_new(V_NUMBER);
702✔
459
   vlog_set_loc(v, CURRENT_LOC);
702✔
460
   vlog_set_number(v, number_new(state.last_lval.str));
702✔
461
   free(state.last_lval.str);
702✔
462
   return v;
702✔
463
}
464

465
static vlog_node_t p_integral_number(void)
575✔
466
{
467
   // decimal_number | octal_number | binary_number | hex_number
468

469
   BEGIN("integral number");
1,150✔
470

471
   if (peek() == tUNSIGNED)
575✔
472
      return p_unsigned_number();
519✔
473
   else {
474
      consume(tNUMBER);
56✔
475

476
      vlog_node_t v = vlog_new(V_NUMBER);
56✔
477
      vlog_set_loc(v, CURRENT_LOC);
56✔
478
      vlog_set_number(v, number_new(state.last_lval.str));
56✔
479
      free(state.last_lval.str);
56✔
480
      return v;
56✔
481
   }
482
}
483

484
static vlog_node_t p_real_number(void)
6✔
485
{
486
   // fixed_point_number
487
   //   | unsigned_number [ . unsigned_number ] exp [ sign ] unsigned_number
488

489
   BEGIN("real number");
6✔
490

491
   consume(tREAL);
6✔
492

493
   vlog_node_t v = vlog_new(V_REAL);
6✔
494
   vlog_set_dval(v, state.last_lval.real);
6✔
495
   vlog_set_loc(v, CURRENT_LOC);
6✔
496
   return v;
6✔
497
}
498

499
static vlog_node_t p_number(void)
577✔
500
{
501
   // integral_number | real_number
502

503
   BEGIN("number");
1,154✔
504

505
   if (peek() == tREAL)
577✔
506
      return p_real_number();
6✔
507
   else
508
      return p_integral_number();
571✔
509
}
510

511
static vlog_node_t p_string_literal(void)
298✔
512
{
513
   // " { Any_ASCII_Characters } "
514

515
   BEGIN("string literal");
298✔
516

517
   consume(tSTRING);
298✔
518

519
   vlog_node_t v = vlog_new(V_STRING);
298✔
520
   vlog_set_loc(v, CURRENT_LOC);
298✔
521

522
   state.last_lval.str[strlen(state.last_lval.str) - 1] = '\0';
298✔
523
   vlog_set_text(v, state.last_lval.str + 1);
298✔
524
   free(state.last_lval.str);
298✔
525

526
   return v;
298✔
527
}
528

529
static vlog_node_t p_primary_literal(void)
875✔
530
{
531
   // number | time_literal | unbased_unsized_literal | string_literal
532

533
   BEGIN("primary literal");
1,750✔
534

535
   switch (peek()) {
875✔
536
   case tNUMBER:
577✔
537
   case tUNSIGNED:
538
   case tREAL:
539
      return p_number();
577✔
540
   case tSTRING:
298✔
541
      return p_string_literal();
298✔
542
   default:
×
543
      one_of(tNUMBER, tUNSIGNED, tREAL, tSTRING);
×
544
      return dummy_expression();
×
545
   }
546
}
547

548
static vlog_node_t p_constant_bit_select(ident_t id)
184✔
549
{
550
   // { [ constant_expression ] }
551

552
   EXTEND("constant bit select");
368✔
553

554
   // Checked for constant-ness later
555
   return p_bit_select(id);
184✔
556
}
557

558
static vlog_node_t p_constant_select(ident_t id)
184✔
559
{
560
   // [ { . member_identifier constant_bit_select } . member_identifier ]
561
   //    constant_bit_select [ [ constant_part_select_range ] ]
562

563
   EXTEND("constant select");
368✔
564

565
   return p_constant_bit_select(id);
184✔
566
}
567

568
static vlog_node_t p_constant_expression(void)
123✔
569
{
570
   // constant_primary | unary_operator { attribute_instance } constant_primary
571
   //   | constant_expression binary_operator { attribute_instance }
572
   //       constant_expression
573
   //   | constant_expression ? { attribute_instance }
574
   //       constant_expression : constant_expression
575

576
   BEGIN("constant expression");
246✔
577

578
   // Checked for constant-ness later
579
   return p_expression();
123✔
580
}
581

582
static void p_constant_range(vlog_node_t *left, vlog_node_t *right)
60✔
583
{
584
   // constant_expression : constant_expression
585

586
   BEGIN("constant range");
60✔
587

588
   *left = p_constant_expression();
60✔
589

590
   consume(tCOLON);
60✔
591

592
   *right = p_constant_expression();
60✔
593
}
60✔
594

595
static vlog_node_t p_packed_dimension(void)
57✔
596
{
597
   // [ constant_range ] | unsized_dimension
598

599
   BEGIN("packed dimension");
57✔
600

601
   consume(tLSQUARE);
57✔
602

603
   vlog_node_t left, right;
57✔
604
   p_constant_range(&left, &right);
57✔
605

606
   consume(tRSQUARE);
57✔
607

608
   vlog_node_t v = vlog_new(V_DIMENSION);
57✔
609
   vlog_set_subkind(v, V_DIM_PACKED);
57✔
610
   vlog_set_left(v, left);
57✔
611
   vlog_set_right(v, right);
57✔
612
   vlog_set_loc(v, CURRENT_LOC);
57✔
613

614
   return v;
57✔
615
}
616

617
static vlog_node_t p_unpacked_dimension(void)
3✔
618
{
619
   // [ constant_range ] | [ constant_expression ]
620

621
   BEGIN("unpacked dimension");
3✔
622

623
   consume(tLSQUARE);
3✔
624

625
   vlog_node_t left, right;
3✔
626
   p_constant_range(&left, &right);
3✔
627

628
   consume(tRSQUARE);
3✔
629

630
   vlog_node_t v = vlog_new(V_DIMENSION);
3✔
631
   vlog_set_subkind(v, V_DIM_UNPACKED);
3✔
632
   vlog_set_left(v, left);
3✔
633
   vlog_set_right(v, right);
3✔
634
   vlog_set_loc(v, CURRENT_LOC);
3✔
635

636
   return v;
3✔
637
}
638

639
static vlog_node_t p_data_type_or_void(void)
9✔
640
{
641
   // data_type | void
642

643
   BEGIN("data type or void");
18✔
644

645
   if (optional(tVOID))
9✔
646
      return NULL;
647
   else
648
      return p_data_type();
9✔
649
}
650

651
static void p_struct_union_member(vlog_node_t v)
9✔
652
{
653
   // { attribute_instance } [ random_qualifier ] data_type_or_void
654
   //    list_of_variable_decl_assignments ;
655

656
   BEGIN("struct or union member");
18✔
657

658
   while (peek() == tATTRBEGIN)
9✔
659
      p_attribute_instance();
×
660

661
   vlog_node_t dt = p_data_type_or_void();
9✔
662
   p_list_of_variable_decl_assignments(v, dt);
9✔
663

664
   consume(tSEMI);
9✔
665
}
9✔
666

667
static void p_enum_name_declaration(vlog_node_t parent)
4✔
668
{
669
   // enum_identifier [ [ integral_number [ : integral_number ] ] ]
670
   //   [ = constant_expression ]
671

672
   BEGIN("enum name declaration");
8✔
673

674
   vlog_node_t v = vlog_new(V_ENUM_NAME);
4✔
675
   vlog_set_ident(v, p_identifier());
4✔
676
   vlog_set_type(v, parent);
4✔
677

678
   vlog_add_decl(parent, v);
4✔
679
}
4✔
680

681
static vlog_node_t p_integer_atom_type(void)
14✔
682
{
683
   // byte | shortint | int | longint | integer | time
684

685
   BEGIN("integer atom type");
14✔
686

687
   data_type_t dt = DT_BYTE;
14✔
688
   switch (one_of(tBYTE, tSHORTINT, tSVINT, tLONGINT, tINTEGER, tTIME)) {
14✔
689
   case tBYTE:     dt = DT_BYTE; break;
690
   case tSHORTINT: dt = DT_SHORTINT; break;
691
   case tSVINT:    dt = DT_INT; break;
692
   case tLONGINT:  dt = DT_LONGINT; break;
693
   case tINTEGER:  dt = DT_INTEGER; break;
694
   case tTIME:     dt = DT_TIME; break;
695
   }
696

697
   vlog_node_t v = vlog_new(V_DATA_TYPE);
14✔
698
   vlog_set_subkind(v, dt);
14✔
699
   vlog_set_loc(v, &state.last_loc);
14✔
700
   return v;
14✔
701
}
702

703
static vlog_node_t p_integer_vector_type(void)
126✔
704
{
705
   //  bit | logic | reg
706

707
   BEGIN("integer vector type");
126✔
708

709
   data_type_t dt = DT_LOGIC;
126✔
710
   switch (one_of(tBIT, tLOGIC, tREG)) {
126✔
711
   case tBIT:    dt = DT_BIT; break;
3✔
712
   case tLOGIC:
713
   case tREG:    dt = DT_LOGIC; break;
714
   }
715

716
   vlog_node_t v = vlog_new(V_DATA_TYPE);
126✔
717
   vlog_set_subkind(v, dt);
126✔
718
   vlog_set_loc(v, &state.last_loc);
126✔
719
   return v;
126✔
720
}
721

722
static vlog_node_t p_non_integer_type(void)
5✔
723
{
724
   // shortreal | real | realtime
725

726
   BEGIN("non-integer type");
5✔
727

728
   data_type_t dt = DT_REAL;
5✔
729
   switch (one_of(tSVREAL, tSHORTREAL, tREALTIME)) {
5✔
730
   case tSVREAL:    dt = DT_REAL; break;
731
   case tSHORTREAL: dt = DT_SHORTREAL; break;
1✔
732
   case tREALTIME:  dt = DT_REALTIME; break;
1✔
733
   }
734

735
   vlog_node_t v = vlog_new(V_DATA_TYPE);
5✔
736
   vlog_set_subkind(v, dt);
5✔
737
   vlog_set_loc(v, &state.last_loc);
5✔
738
   return v;
5✔
739
}
740

741
static vlog_node_t p_struct_union(void)
5✔
742
{
743
   // struct | union [ tagged ]
744

745
   BEGIN("struct or union");
10✔
746

747
   switch (one_of(tSTRUCT, tUNION)) {
5✔
748
   case tUNION:
2✔
749
      {
750
         vlog_node_t v = vlog_new(V_UNION_DECL);
2✔
751
         optional(tTAGGED);
2✔
752
         return v;
2✔
753
      }
754
   case tSTRUCT:
3✔
755
   default:
756
      return vlog_new(V_STRUCT_DECL);
3✔
757
   }
758
}
759

760
static vlog_node_t p_data_type(void)
152✔
761
{
762
   // integer_vector_type [ signing ] { packed_dimension }
763
   //   | integer_atom_type [ signing ] | non_integer_type
764
   //   | struct_union [ packed [ signing ] ]
765
   //       { struct_union_member { struct_union_member } } { packed_dimension }
766
   //   | enum [ enum_base_type ] { enum_name_declaration
767
   //       { , enum_name_declaration } } { packed_dimension }
768
   //   | string | chandle
769
   //   | virtual [ interface ] interface_identifier
770
   //       [ parameter_value_assignment ] [ . modport_identifier ]
771
   //   | [ class_scope | package_scope ] type_identifier { packed_dimension }
772
   //   | class_type | event | ps_covergroup_identifier | type_reference
773

774
   BEGIN("data type");
304✔
775

776
   switch (peek()) {
152✔
777
   case tBIT:
126✔
778
   case tLOGIC:
779
   case tREG:
780
      {
781
         vlog_node_t v = p_integer_vector_type();
126✔
782

783
         while (peek() == tLSQUARE)
152✔
784
            vlog_add_range(v, p_packed_dimension());
26✔
785

786
         return v;
787
      }
788

789
   case tBYTE:
14✔
790
   case tSHORTINT:
791
   case tSVINT:
792
   case tLONGINT:
793
   case tINTEGER:
794
   case tTIME:
795
      return p_integer_atom_type();
14✔
796

797
   case tSVREAL:
5✔
798
   case tREALTIME:
799
   case tSHORTREAL:
800
      return p_non_integer_type();
5✔
801

802
   case tSTRUCT:
5✔
803
   case tUNION:
804
      {
805
         vlog_node_t v = p_struct_union();
5✔
806

807
         (void)optional(tPACKED);
5✔
808

809
         consume(tLBRACE);
5✔
810

811
         do {
9✔
812
            p_struct_union_member(v);
9✔
813
         } while (not_at_token(tRBRACE));
9✔
814

815
         consume(tRBRACE);
5✔
816

817
         if (peek() == tLSQUARE)
5✔
818
            vlog_add_range(v, p_packed_dimension());
×
819

820
         vlog_set_loc(v, CURRENT_LOC);
5✔
821
         return v;
5✔
822
      }
823

824
   case tENUM:
2✔
825
      {
826
         consume(tENUM);
2✔
827

828
         vlog_node_t v = vlog_new(V_ENUM_DECL);
2✔
829

830
         consume(tLBRACE);
2✔
831

832
         do {
4✔
833
            p_enum_name_declaration(v);
4✔
834
         } while (optional(tCOMMA));
4✔
835

836
         consume(tRBRACE);
2✔
837

838
         while (peek() == tLSQUARE)
3✔
839
            vlog_add_range(v, p_packed_dimension());
1✔
840

841
         vlog_set_loc(v, CURRENT_LOC);
2✔
842
         return v;
2✔
843
      }
844

845
   default:
×
846
      one_of(tBIT, tLOGIC, tREG, tBYTE, tSHORTINT, tSVINT, tLONGINT, tINTEGER,
×
847
             tTIME, tSVREAL, tREALTIME, tSHORTREAL, tSTRUCT, tUNION, tENUM);
848
      return logic_type();
×
849
   }
850
}
851

852
static vlog_node_t p_implicit_data_type(void)
167✔
853
{
854
   // [ signing ] { packed_dimension }
855

856
   BEGIN("implicit data type");
167✔
857

858
   vlog_node_t v = vlog_new(V_DATA_TYPE);
167✔
859
   vlog_set_subkind(v, DT_LOGIC);
167✔
860

861
   while (peek() == tLSQUARE)
197✔
862
      vlog_add_range(v, p_packed_dimension());
30✔
863

864
   vlog_set_loc(v, CURRENT_LOC);
167✔
865
   return v;
167✔
866
}
867

868
static vlog_node_t p_data_type_or_implicit(void)
301✔
869
{
870
   // data_type | implicit_data_type
871

872
   BEGIN("data type or implicit");
602✔
873

874
   if (scan(tREG, tSTRUCT, tUNION, tENUM, tSVINT, tINTEGER, tSVREAL,
301✔
875
            tSHORTREAL, tREALTIME, tLOGIC, tBIT))
876
      return p_data_type();
135✔
877
   else
878
      return p_implicit_data_type();
166✔
879
}
880

881
static vlog_node_t p_net_port_type(void)
90✔
882
{
883
   // [ net_type ] data_type_or_implicit | net_type_identifier
884
   //   | interconnect implicit_data_type
885

886
   BEGIN("net port type");
180✔
887

888
   return p_data_type_or_implicit();
90✔
889
}
890

891
static vlog_node_t p_var_data_type(void)
3✔
892
{
893
   // data_type | var data_type_or_implicit
894

895
   BEGIN("var data type");
6✔
896

897
   return p_data_type();
3✔
898
}
899

900
static vlog_node_t p_variable_port_type(void)
3✔
901
{
902
   // var_data_type
903

904
   BEGIN("variable port type");
6✔
905

906
   return p_var_data_type();
3✔
907
}
908

909
static void p_list_of_port_identifiers(vlog_node_t mod, v_port_kind_t kind,
57✔
910
                                       bool isreg, vlog_node_t datatype)
911
{
912
   // port_identifier { unpacked_dimension }
913
   //    { , port_identifier { unpacked_dimension } }
914

915
   BEGIN("list of port identifiers");
114✔
916

917
   do {
65✔
918
      ident_t id, ext;
65✔
919
      p_external_identifier(&id, &ext);
65✔
920

921
      vlog_node_t v = vlog_new(V_PORT_DECL);
65✔
922
      vlog_set_subkind(v, kind);
65✔
923
      vlog_set_ident(v, id);
65✔
924
      vlog_set_ident2(v, ext);
65✔
925
      vlog_set_type(v, datatype);
65✔
926
      vlog_set_loc(v, &state.last_loc);
65✔
927

928
      vlog_add_decl(mod, v);
65✔
929

930
      if (isreg) {
65✔
931
         vlog_node_t reg = vlog_new(V_VAR_DECL);
3✔
932
         vlog_set_loc(reg, vlog_loc(v));
3✔
933
         vlog_set_ident(reg, id);
3✔
934
         vlog_set_type(reg, datatype);
3✔
935

936
         vlog_add_decl(mod, reg);
3✔
937
      }
938

939
      vlog_node_t ref = vlog_new(V_REF);
65✔
940
      vlog_set_loc(ref, CURRENT_LOC);
65✔
941
      vlog_set_ident(ref, id);
65✔
942
      vlog_set_ref(ref, v);
65✔
943

944
      vlog_add_port(mod, ref);
65✔
945
   } while (optional(tCOMMA));
65✔
946
}
57✔
947

948
static void p_inout_declaration(vlog_node_t mod)
1✔
949
{
950
   // inout net_port_type list_of_port_identifiers
951

952
   BEGIN("inout declaration");
2✔
953

954
   consume(tINOUT);
1✔
955

956
   vlog_node_t dt = p_net_port_type();
1✔
957
   p_list_of_port_identifiers(mod, V_PORT_INOUT, false, dt);
1✔
958
}
1✔
959

960
static void p_input_declaration(vlog_node_t mod)
33✔
961
{
962
   // input net_port_type list_of_port_identifiers
963
   //   | input variable_port_type list_of_variable_identifiers
964

965
   BEGIN("input declaration");
66✔
966

967
   consume(tINPUT);
33✔
968

969
   bool isreg = false;
33✔
970
   vlog_node_t dt;
33✔
971
   switch (peek()) {
33✔
972
   case tREG:
×
973
      dt = p_variable_port_type();
×
974
      isreg = true;
×
975
      break;
×
976
   default:
33✔
977
      dt = p_net_port_type();
33✔
978
      break;
33✔
979
   }
980

981
   p_list_of_port_identifiers(mod, V_PORT_INPUT, isreg, dt);
33✔
982
}
33✔
983

984
static void p_output_declaration(vlog_node_t mod)
23✔
985
{
986
   // output net_port_type list_of_port_identifiers
987
   //   | output variable_port_type list_of_variable_port_identifiers
988

989
   BEGIN("output declaration");
46✔
990

991
   consume(tOUTPUT);
23✔
992

993
   bool isreg = false;
23✔
994
   vlog_node_t dt;
23✔
995
   switch (peek()) {
23✔
996
   case tREG:
3✔
997
      dt = p_variable_port_type();
3✔
998
      isreg = true;
3✔
999
      break;
3✔
1000
   default:
20✔
1001
      dt = p_net_port_type();
20✔
1002
      break;
20✔
1003
   }
1004

1005
   p_list_of_port_identifiers(mod, V_PORT_OUTPUT, isreg, dt);
23✔
1006
}
23✔
1007

1008
static void p_port_declaration(vlog_node_t mod)
57✔
1009
{
1010
   // { attribute_instance } inout_declaration
1011
   //   | { attribute_instance } input_declaration
1012
   //   | { attribute_instance } output_declaration
1013
   //   | { attribute_instance } ref_declaration
1014
   //   | { attribute_instance } interface_port_declaration
1015

1016
   BEGIN("port declaration");
114✔
1017

1018
   switch (peek()) {
57✔
1019
   case tINOUT: p_inout_declaration(mod); break;
1✔
1020
   case tINPUT: p_input_declaration(mod); break;
33✔
1021
   case tOUTPUT: p_output_declaration(mod); break;
23✔
1022
   default: should_not_reach_here();
1023
   }
1024
}
57✔
1025

1026
static vlog_node_t p_net_port_header(v_port_kind_t *kind, bool *isreg)
36✔
1027
{
1028
   // [ port_direction ] net_port_type
1029

1030
   BEGIN("net port header");
72✔
1031

1032
   if (optional(tINPUT)) {
36✔
1033
      *kind = V_PORT_INPUT;
21✔
1034
      *isreg = (peek() == tREG);
21✔
1035
   }
1036
   else if (optional(tINOUT)) {
15✔
1037
      *kind = V_PORT_INOUT;
×
1038
      *isreg = false;
×
1039
   }
1040
   else if (optional(tOUTPUT)) {
15✔
1041
      *kind = V_PORT_OUTPUT;
15✔
1042
      *isreg = (peek() == tREG);
15✔
1043
   }
1044

1045
   return p_net_port_type();
36✔
1046
}
1047

1048
static vlog_node_t p_bit_select(ident_t id)
1,120✔
1049
{
1050
   // { [ expression ] }
1051

1052
   EXTEND("bit select");
2,240✔
1053

1054
   if (peek() == tLSQUARE) {
1,120✔
1055
      vlog_node_t v = vlog_new(V_BIT_SELECT);
13✔
1056
      vlog_set_ident(v, id);
13✔
1057

1058
      while (optional(tLSQUARE)) {
26✔
1059
         vlog_add_param(v, p_expression());
13✔
1060
         consume(tRSQUARE);
13✔
1061
      }
1062

1063
      vlog_set_loc(v, CURRENT_LOC);
13✔
1064
      return v;
13✔
1065
   }
1066
   else {
1067
      vlog_node_t v = vlog_new(V_REF);
1,107✔
1068
      vlog_set_ident(v, id);
1,107✔
1069
      vlog_set_loc(v, CURRENT_LOC);
1,107✔
1070
      return v;
1,107✔
1071
   }
1072
}
1073

1074

1075
static vlog_node_t p_select(ident_t id)
936✔
1076
{
1077
   // [ { . member_identifier bit_select } . member_identifier ]
1078
   //    bit_select [ [ part_select_range ] ]
1079

1080
   EXTEND("select");
1,872✔
1081

1082
   return p_bit_select(id);
936✔
1083
}
1084

1085
static void p_list_of_arguments(vlog_node_t call)
298✔
1086
{
1087
   // [ expression ] { , [ expression ] } { , . identifier ( [ expression ] ) }
1088
   //    | . identifier ( [ expression ] ) { , . identifier ( [ expression ] ) }
1089

1090
   BEGIN("list of arguments");
596✔
1091

1092
   do {
575✔
1093
      if (peek() == tCOMMA) {
575✔
1094
         vlog_node_t v = vlog_new(V_EMPTY);
9✔
1095
         vlog_set_loc(v, &state.last_loc);
9✔
1096
         vlog_add_param(call, v);
9✔
1097
      }
1098
      else
1099
         vlog_add_param(call, p_expression());
566✔
1100
   } while (optional(tCOMMA));
575✔
1101
}
298✔
1102

1103
static vlog_node_t p_system_tf_call(vlog_kind_t kind)
430✔
1104
{
1105
   // system_tf_identifier [ ( list_of_arguments ) ]
1106

1107
   BEGIN("system task or function call");
430✔
1108

1109
   vlog_node_t v = vlog_new(kind);
430✔
1110
   vlog_set_ident(v, p_system_tf_identifier());
430✔
1111

1112
   if (optional(tLPAREN)) {
430✔
1113
      p_list_of_arguments(v);
298✔
1114
      consume(tRPAREN);
298✔
1115
   }
1116

1117
   vlog_set_loc(v, CURRENT_LOC);
430✔
1118
   return v;
430✔
1119
}
1120

1121
static vlog_node_t p_subroutine_call(vlog_kind_t kind)
430✔
1122
{
1123
   // tf_call | system_tf_call | method_call | [ std:: ] randomize_call
1124

1125
   BEGIN("subroutine call");
860✔
1126

1127
   return p_system_tf_call(kind);
430✔
1128
}
1129

1130
static vlog_node_t p_mintypmax_expression(void)
12✔
1131
{
1132
   // expression | expression : expression : expression
1133

1134
   BEGIN("mintypmax expression");
24✔
1135

1136
   return p_expression();
12✔
1137
}
1138

1139
static vlog_node_t p_concatenation(vlog_node_t head)
8✔
1140
{
1141
   // { expression { , expression } }
1142

1143
   BEGIN_WITH_HEAD("concatenation", head);
8✔
1144

1145
   if (head == NULL) {
8✔
1146
      consume(tLBRACE);
2✔
1147
      head = p_expression();
2✔
1148
   }
1149

1150
   vlog_node_t v = vlog_new(V_CONCAT);
8✔
1151
   vlog_add_param(v, head);
8✔
1152

1153
   while (optional(tCOMMA))
14✔
1154
      vlog_add_param(v, p_expression());
6✔
1155

1156
   consume(tRBRACE);
8✔
1157

1158
   vlog_set_loc(v, CURRENT_LOC);
8✔
1159
   return v;
8✔
1160
}
1161

1162
static vlog_node_t p_multiple_concatenation(vlog_node_t head)
2✔
1163
{
1164
   // { expression concatenation }
1165

1166
   BEGIN_WITH_HEAD("multiple concatenation", head);
2✔
1167

1168
   vlog_node_t v = p_concatenation(NULL);
2✔
1169
   vlog_set_value(v, head);
2✔
1170

1171
   consume(tRBRACE);
2✔
1172

1173
   vlog_set_loc(v, CURRENT_LOC);
2✔
1174
   return v;
2✔
1175
}
1176

1177
static vlog_node_t p_primary(void)
1,571✔
1178
{
1179
   // primary_literal | empty_queue
1180
   // | [ class_qualifier | package_scope ] hierarchical_identifier select
1181
   // | concatenation [ [ range_expression ] ]
1182
   // | multiple_concatenation [ [ range_expression ] ]
1183
   // | function_subroutine_call
1184
   // | let_expression | ( mintypmax_expression ) | cast
1185
   // | assignment_pattern_expression | streaming_concatenation
1186
   // | sequence_method_call | this | $ | null
1187

1188
   BEGIN("primary");
3,142✔
1189

1190
   switch (peek()) {
1,571✔
1191
   case tID:
645✔
1192
      return p_select(p_identifier());
645✔
1193
   case tSTRING:
875✔
1194
   case tNUMBER:
1195
   case tUNSIGNED:
1196
   case tREAL:
1197
      return p_primary_literal();
875✔
1198
   case tSYSTASK:
40✔
1199
      return p_subroutine_call(V_SYS_FCALL);
40✔
1200
   case tLPAREN:
3✔
1201
      {
1202
         consume(tLPAREN);
3✔
1203
         vlog_node_t expr = p_mintypmax_expression();
3✔
1204
         consume(tRPAREN);
3✔
1205
         return expr;
3✔
1206
      }
1207
   case tLBRACE:
8✔
1208
      {
1209
         consume(tLBRACE);
8✔
1210

1211
         vlog_node_t head = p_expression();
8✔
1212
         if (peek() == tLBRACE)
8✔
1213
            return p_multiple_concatenation(head);
2✔
1214
         else
1215
            return p_concatenation(head);
6✔
1216
      }
1217
   default:
×
1218
      one_of(tID, tSTRING, tNUMBER, tUNSIGNED, tREAL, tSYSTASK, tLPAREN,
×
1219
             tLBRACE);
1220
      return p_select(error_marker());
×
1221
   }
1222
}
1223

1224
static vlog_binary_t p_binary_operator(void)
217✔
1225
{
1226
   // + | - | * | / | % | == | != | === | !== | ==? | !=? | && | ||
1227
   //  | ** | < | <= | > | >= | & | | | ^ | ^~ | ~^ | >> | <<
1228
   //  | >>> | <<< | -> | <->
1229

1230
   BEGIN("binary operator");
434✔
1231

1232
   switch (one_of(tBAR, tPLUS, tAMP, tCASEEQ, tCASENEQ, tLOGOR,
217✔
1233
                  tLOGEQ, tLOGNEQ, tDBLAMP, tSHIFTLL, tSHIFTRL,
1234
                  tSHIFTLA, tSHIFTRA, tLT, tGT, tLE, tGE, tMINUS,
1235
                  tTIMES, tOVER, tPERCENT)) {
1236
   case tBAR:     return V_BINARY_OR;
1237
   case tAMP:     return V_BINARY_AND;
18✔
1238
   case tCASEEQ:  return V_BINARY_CASE_EQ;
14✔
1239
   case tCASENEQ: return V_BINARY_CASE_NEQ;
87✔
1240
   case tLOGEQ:   return V_BINARY_LOG_EQ;
9✔
1241
   case tLOGNEQ:  return V_BINARY_LOG_NEQ;
×
1242
   case tLOGOR:   return V_BINARY_LOG_OR;
17✔
1243
   case tDBLAMP:  return V_BINARY_LOG_AND;
4✔
1244
   case tSHIFTLL: return V_BINARY_SHIFT_LL;
1✔
1245
   case tSHIFTRL: return V_BINARY_SHIFT_RL;
1✔
1246
   case tSHIFTLA: return V_BINARY_SHIFT_LA;
1✔
1247
   case tSHIFTRA: return V_BINARY_SHIFT_RA;
1✔
1248
   case tLT:      return V_BINARY_LT;
7✔
1249
   case tGT:      return V_BINARY_GT;
7✔
1250
   case tLE:      return V_BINARY_LEQ;
6✔
1251
   case tGE:      return V_BINARY_GEQ;
6✔
1252
   case tMINUS:   return V_BINARY_MINUS;
4✔
1253
   case tTIMES:   return V_BINARY_TIMES;
2✔
1254
   case tOVER:    return V_BINARY_DIVIDE;
1✔
1255
   case tPERCENT: return V_BINARY_MOD;
1✔
1256
   case tPLUS:
17✔
1257
   default:       return V_BINARY_PLUS;
17✔
1258
   }
1259
}
1260

1261
static vlog_unary_t p_unary_operator(void)
47✔
1262
{
1263
   // + | - | ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~
1264

1265
   BEGIN("unary operator");
94✔
1266

1267
   switch (one_of(tMINUS, tPLUS, tTILDE, tBANG, tAMP, tBAR, tCARET)) {
47✔
1268
   case tMINUS: return V_UNARY_NEG;
1269
   case tTILDE: return V_UNARY_BITNEG;
21✔
1270
   case tBANG: return V_UNARY_NOT;
18✔
1271
   case tAMP: return V_UNARY_AND;
1✔
1272
   case tBAR: return V_UNARY_OR;
1✔
1273
   case tCARET: return V_UNARY_XOR;
1✔
1274
   case tPLUS:
1✔
1275
   default: return V_UNARY_IDENTITY;
1✔
1276
   }
1277
}
1278

1279
static vlog_incdec_t p_inc_or_dec_operator(void)
2✔
1280
{
1281
   // ++ | --
1282

1283
   BEGIN("inc or dec operator");
4✔
1284

1285
   switch (one_of(tPLUSPLUS, tMINUSMINUS)) {
2✔
1286
   case tMINUSMINUS: return V_INCDEC_MINUS;
1287
   case tPLUSPLUS:
1✔
1288
   default: return V_INCDEC_PLUS;
1✔
1289
   }
1290
}
1291

1292
static vlog_node_t p_inc_or_dec_expression(vlog_node_t head)
2✔
1293
{
1294
   // inc_or_dec_operator { attribute_instance } variable_lvalue
1295
   //   | variable_lvalue { attribute_instance } inc_or_dec_operator
1296

1297
   BEGIN_WITH_HEAD("inc or dec expression", head);
2✔
1298

1299
   vlog_node_t v = vlog_new(head ? V_POSTFIX : V_PREFIX);
3✔
1300
   vlog_set_subkind(v, p_inc_or_dec_operator());
2✔
1301
   vlog_set_target(v, head ?: p_variable_lvalue());
2✔
1302

1303
   vlog_set_loc(v, CURRENT_LOC);
2✔
1304
   return v;
2✔
1305
}
1306

1307
static vlog_node_t p_nonbinary_expression(void)
1,572✔
1308
{
1309
   // primary | unary_operator { attribute_instance } primary
1310
   //   | inc_or_dec_expression | ( operator_assignment )
1311
   //   | conditional_expression | inside_expression | tagged_union_expression
1312

1313
   switch (peek()) {
1,572✔
1314
   case tID:
1,524✔
1315
   case tSTRING:
1316
   case tNUMBER:
1317
   case tUNSIGNED:
1318
   case tREAL:
1319
   case tSYSTASK:
1320
   case tLPAREN:
1321
   case tLBRACE:
1322
      return p_primary();
1,524✔
1323
   case tMINUS:
47✔
1324
   case tPLUS:
1325
   case tTILDE:
1326
   case tBANG:
1327
   case tAMP:
1328
   case tBAR:
1329
   case tCARET:
1330
      {
1331
         vlog_node_t v = vlog_new(V_UNARY);
47✔
1332
         vlog_set_subkind(v, p_unary_operator());
47✔
1333
         vlog_set_value(v, p_primary());
47✔
1334
         vlog_set_loc(v, CURRENT_LOC);
47✔
1335
         return v;
47✔
1336
      }
1337
   case tPLUSPLUS:
×
1338
   case tMINUSMINUS:
1339
      return p_inc_or_dec_expression(NULL);
×
1340
   default:
1✔
1341
      one_of(tID, tSTRING, tNUMBER, tUNSIGNED, tREAL, tSYSTASK, tLPAREN,
1✔
1342
             tLBRACE, tMINUS, tTILDE, tBANG, tAMP, tBAR, tCARET, tPLUSPLUS,
1343
             tMINUSMINUS);
1344
      return p_select(error_marker());
1✔
1345
   }
1346
}
1347

1348
static vlog_node_t p_conditional_expression(vlog_node_t head)
2✔
1349
{
1350
   // cond_predicate ? { attribute_instance } expression : expression
1351

1352
   BEGIN("conditional expression");
2✔
1353

1354
   vlog_node_t v = vlog_new(V_COND_EXPR);
2✔
1355
   vlog_set_value(v, head);
2✔
1356

1357
   consume(tQUESTION);
2✔
1358

1359
   while (peek() == tATTRBEGIN)
2✔
1360
      p_attribute_instance();
×
1361

1362
   vlog_set_left(v, p_expression());
2✔
1363

1364
   consume(tCOLON);
2✔
1365

1366
   vlog_set_right(v, p_expression());
2✔
1367

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

1372
static bool peek_binary_operator(int *prec)
1,841✔
1373
{
1374
   // See LRM 1800-2017 section 11.3.2 for operator precedence table
1375

1376
   switch (peek()) {
1,841✔
1377
   case tTIMES:
7✔
1378
   case tOVER:
1379
   case tPERCENT:  *prec = 11; return true;
7✔
1380
   case tPLUS:
25✔
1381
   case tMINUS:    *prec = 10; return true;
25✔
1382
   case tSHIFTLL:
4✔
1383
   case tSHIFTRL:
1384
   case tSHIFTLA:
1385
   case tSHIFTRA:  *prec = 9;  return true;
4✔
1386
   case tLT:
26✔
1387
   case tGT:
1388
   case tLE:
1389
   case tGE:       *prec = 8;  return true;
26✔
1390
   case tCASEEQ:
131✔
1391
   case tCASENEQ:
1392
   case tLOGEQ:
1393
   case tLOGNEQ:   *prec = 7;  return true;
131✔
1394
   case tAMP:      *prec = 6;  return true;
19✔
1395
   case tBAR:      *prec = 4;  return true;
14✔
1396
   case tDBLAMP:   *prec = 3;  return true;
7✔
1397
   case tLOGOR:    *prec = 2;  return true;
33✔
1398
   case tQUESTION: *prec = 1;  return true;
2✔
1399
   default:
1400
      return false;
1401
   }
1402
}
1403

1404
static vlog_node_t p_binary_expression(vlog_node_t lhs, int min_prec)
1,380✔
1405
{
1406
   // Precedence climbing method, see
1407
   //    https://en.wikipedia.org/wiki/Operator-precedence_parser
1408

1409
   int prec1;
1,380✔
1410
   while (peek_binary_operator(&prec1) && prec1 >= min_prec) {
1,599✔
1411
      if (peek() == tQUESTION)
219✔
1412
         lhs = p_conditional_expression(lhs);
2✔
1413
      else {
1414
         vlog_node_t v = vlog_new(V_BINARY);
217✔
1415
         vlog_set_subkind(v, p_binary_operator());
217✔
1416
         vlog_set_left(v, lhs);
217✔
1417

1418
         vlog_node_t rhs = p_nonbinary_expression();
217✔
1419

1420
         int prec2;
217✔
1421
         while (peek_binary_operator(&prec2) && prec2 > prec1)
242✔
1422
            rhs = p_binary_expression(rhs, prec1 + (prec2 > prec1));
25✔
1423

1424
         vlog_set_right(v, rhs);
217✔
1425
         vlog_set_loc(v, CURRENT_LOC);
217✔
1426
         lhs = v;
217✔
1427
      }
1428
   }
1429

1430
   return lhs;
1,380✔
1431
}
1432

1433
static vlog_node_t p_expression(void)
1,355✔
1434
{
1435
   // primary | unary_operator { attribute_instance } primary
1436
   //   | inc_or_dec_expression | ( operator_assignment )
1437
   //   | expression binary_operator { attribute_instance } expression
1438
   //   | conditional_expression | inside_expression | tagged_union_expression
1439

1440
   BEGIN("expression");
2,710✔
1441

1442
   vlog_node_t head = p_nonbinary_expression();
1,355✔
1443
   return p_binary_expression(head, 0);
1,355✔
1444
}
1445

1446
static void p_event_expression(vlog_node_t ctrl)
71✔
1447
{
1448
   // [ edge_identifier ] expression [ iff expression ]
1449
   //   | sequence_instance [ iff expression ]
1450
   //   | event_expression or event_expression
1451
   //   | event_expression , event_expression
1452
   //   | ( event_expression )
1453

1454
   BEGIN("event expression");
142✔
1455

1456
   do {
91✔
1457
      if (optional(tLPAREN)) {
91✔
1458
         p_event_expression(ctrl);
1✔
1459
         consume(tRPAREN);
1✔
1460
      }
1461
      else {
1462
         vlog_node_t v = vlog_new(V_EVENT);
90✔
1463

1464
         if (optional(tPOSEDGE))
90✔
1465
            vlog_set_subkind(v, V_EVENT_POSEDGE);
23✔
1466
         else if (optional(tNEGEDGE))
67✔
1467
            vlog_set_subkind(v, V_EVENT_NEGEDGE);
3✔
1468
         else
1469
            vlog_set_subkind(v, V_EVENT_LEVEL);
64✔
1470

1471
         vlog_set_value(v, p_expression());
90✔
1472
         vlog_set_loc(v, CURRENT_LOC);
90✔
1473

1474
         vlog_add_param(ctrl, v);
90✔
1475
      }
1476
   } while (optional(tOR) || optional(tCOMMA));
91✔
1477
}
71✔
1478

1479
static vlog_node_t p_cond_predicate(void)
126✔
1480
{
1481
   // expression_or_cond_pattern { &&& expression_or_cond_pattern }
1482

1483
   BEGIN("cond predicate");
252✔
1484

1485
   return p_expression();
126✔
1486
}
1487

1488
static vlog_node_t p_event_control(void)
70✔
1489
{
1490
   // @ hierarchical_event_identifier | @ ( event_expression )
1491
   //    | @* | @ (*) | @ ps_or_hierarchical_sequence_identifier
1492

1493
   BEGIN("event control");
70✔
1494

1495
   consume(tAT);
70✔
1496
   consume(tLPAREN);
70✔
1497

1498
   vlog_node_t v = vlog_new(V_EVENT_CONTROL);
70✔
1499

1500
   p_event_expression(v);
70✔
1501

1502
   consume(tRPAREN);
70✔
1503

1504
   vlog_set_loc(v, CURRENT_LOC);
70✔
1505
   return v;
70✔
1506
}
1507

1508
static vlog_node_t p_delay_value(void)
183✔
1509
{
1510
   // unsigned_number | real_number | ps_identifier | time_literal | 1step
1511

1512
   BEGIN("delay value");
366✔
1513

1514
   return p_unsigned_number();
183✔
1515
}
1516

1517
static vlog_node_t p_delay_control(void)
183✔
1518
{
1519
   // # delay_value | # ( mintypmax_expression )
1520

1521
   BEGIN("delay control");
183✔
1522

1523
   consume(tHASH);
183✔
1524

1525
   vlog_node_t v = vlog_new(V_DELAY_CONTROL);
183✔
1526
   vlog_set_value(v, p_delay_value());
183✔
1527
   vlog_set_loc(v, CURRENT_LOC);
183✔
1528
   return v;
183✔
1529
}
1530

1531
static vlog_node_t p_delay_or_event_control(void)
38✔
1532
{
1533
   // delay_control | event_control | repeat ( expression ) event_control
1534

1535
   BEGIN("delay or event control");
76✔
1536

1537
   return p_delay_control();
38✔
1538
}
1539

1540
static vlog_node_t p_variable_lvalue(void)
290✔
1541
{
1542
   // [ implicit_class_handle . | package_scope ]
1543
   //      hierarchical_variable_identifier select
1544
   //   | { variable_lvalue { , variable_lvalue } }
1545
   //   | [ assignment_pattern_expression_type ]
1546
   //      assignment_pattern_variable_lvalue
1547
   //   | streaming_concatenation
1548

1549
   BEGIN("variable lvalue");
290✔
1550

1551
   ident_t id = p_identifier();
290✔
1552
   vlog_node_t v = p_select(id);
290✔
1553

1554
   vlog_set_loc(v, CURRENT_LOC);
290✔
1555
   return v;
290✔
1556
}
1557

1558
static vlog_node_t p_net_lvalue(void)
123✔
1559
{
1560
   // ps_or_hierarchical_net_identifier constant_select
1561
   //   | { net_lvalue { , net_lvalue } }
1562
   //   | [ assignment_pattern_expression_type ] assignment_pattern_net_lvalue
1563

1564
   BEGIN("net lvalue");
246✔
1565

1566
   if (optional(tLBRACE)) {
123✔
1567
      vlog_node_t v = vlog_new(V_CONCAT);
3✔
1568

1569
      do {
6✔
1570
         vlog_add_param(v, p_net_lvalue());
6✔
1571
      } while (optional(tCOMMA));
6✔
1572

1573
      consume(tRBRACE);
3✔
1574

1575
      vlog_set_loc(v, CURRENT_LOC);
3✔
1576
      return v;
3✔
1577
   }
1578
   else {
1579
      ident_t id = p_identifier();
120✔
1580
      vlog_node_t v = p_constant_select(id);
120✔
1581

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

1587
static vlog_node_t p_operator_assignment(vlog_node_t lhs)
180✔
1588
{
1589
   // variable_lvalue assignment_operator expression
1590

1591
   BEGIN_WITH_HEAD("operator assignment", lhs);
180✔
1592

1593
   consume(tEQ);
180✔
1594

1595
   vlog_node_t v = vlog_new(V_BASSIGN);
180✔
1596
   vlog_set_target(v, lhs);
180✔
1597

1598
   vlog_set_value(v, p_expression());
180✔
1599

1600
   vlog_set_loc(v, CURRENT_LOC);
180✔
1601
   return v;
180✔
1602
}
1603

1604
static vlog_node_t p_blocking_assignment(vlog_node_t lhs)
204✔
1605
{
1606
   // variable_lvalue = delay_or_event_control expression
1607
   //   | nonrange_variable_lvalue = dynamic_array_new
1608
   //   | [ implicit_class_handle . | class_scope | package_scope ]
1609
   //         hierarchical_variable_identifier select != class_new
1610
   //   | operator_assignment
1611

1612
   BEGIN_WITH_HEAD("blocking assignment", lhs);
408✔
1613

1614
   switch (peek_nth(2)) {
204✔
1615
   case tHASH:
25✔
1616
   case tAT:
1617
      {
1618
         consume(tEQ);
25✔
1619

1620
         vlog_node_t v = vlog_new(V_BASSIGN);
25✔
1621
         vlog_set_target(v, lhs);
25✔
1622
         vlog_set_delay(v, p_delay_or_event_control());
25✔
1623
         vlog_set_value(v, p_expression());
25✔
1624

1625
         vlog_set_loc(v, CURRENT_LOC);
25✔
1626
         return v;
25✔
1627
      }
1628
   default:
179✔
1629
      return p_operator_assignment(lhs);
179✔
1630
   }
1631
}
1632

1633
static vlog_node_t p_nonblocking_assignment(vlog_node_t lhs)
82✔
1634
{
1635
   // variable_lvalue <= [ delay_or_event_control ] expression
1636

1637
   BEGIN_WITH_HEAD("non-blocking assignment", lhs);
82✔
1638

1639
   consume(tLE);
82✔
1640

1641
   vlog_node_t v = vlog_new(V_NBASSIGN);
82✔
1642
   vlog_set_target(v, lhs);
82✔
1643

1644
   if (scan(tHASH, tAT))
82✔
1645
      vlog_set_delay(v, p_delay_or_event_control());
13✔
1646

1647
   vlog_set_value(v, p_expression());
82✔
1648

1649
   vlog_set_loc(v, CURRENT_LOC);
82✔
1650
   return v;
82✔
1651
}
1652

1653
static vlog_node_t p_procedural_timing_control(void)
215✔
1654
{
1655
   // delay_control | event_control | cycle_delay
1656

1657
   BEGIN("procedural timing control");
430✔
1658

1659
   switch (peek()) {
215✔
1660
   case tAT:
70✔
1661
      return p_event_control();
70✔
1662
   case tHASH:
145✔
1663
      return p_delay_control();
145✔
1664
   default:
×
1665
      should_not_reach_here();
1666
   }
1667
}
1668

1669
static vlog_node_t p_procedural_timing_control_statement(void)
215✔
1670
{
1671
   // procedural_timing_control statement_or_null
1672

1673
   BEGIN("procedural timing control statement");
215✔
1674

1675
   vlog_node_t v = vlog_new(V_TIMING);
215✔
1676
   vlog_set_value(v, p_procedural_timing_control());
215✔
1677

1678
   vlog_node_t s = p_statement_or_null();
215✔
1679
   if (s != NULL)
215✔
1680
      vlog_add_stmt(v, s);
134✔
1681

1682
   vlog_set_loc(v, CURRENT_LOC);
215✔
1683
   return v;
215✔
1684
}
1685

1686
static vlog_node_t p_seq_block(void)
187✔
1687
{
1688
   // begin [ : block_identifier ] { block_item_declaration }
1689
   //   { statement_or_null } end [ : block_identifier ]
1690

1691
   BEGIN("sequential block");
187✔
1692

1693
   consume(tBEGIN);
187✔
1694

1695
   vlog_node_t v = vlog_new(V_SEQ_BLOCK);
187✔
1696

1697
   if (optional(tCOLON))
187✔
1698
      vlog_set_ident(v, p_identifier());
1✔
1699

1700
   while (not_at_token(tEND)) {
948✔
1701
      vlog_node_t s = p_statement_or_null();
761✔
1702
      if (s != NULL)
761✔
1703
         vlog_add_stmt(v, s);
761✔
1704
   }
1705

1706
   consume(tEND);
187✔
1707

1708
   vlog_set_loc(v, CURRENT_LOC);
187✔
1709
   return v;
187✔
1710
}
1711

1712
static vlog_node_t p_subroutine_call_statement(void)
390✔
1713
{
1714
   // subroutine_call ; | void ' ( function_subroutine_call ) ;
1715

1716
   BEGIN("subroutine call statement");
390✔
1717

1718
   vlog_node_t v = p_subroutine_call(V_SYS_TCALL);
390✔
1719

1720
   consume(tSEMI);
390✔
1721

1722
   vlog_set_loc(v, CURRENT_LOC);
390✔
1723
   return v;
390✔
1724
}
1725

1726
static vlog_node_t p_conditional_statement(void)
122✔
1727
{
1728
   // [ unique_priority ] if ( cond_predicate ) statement_or_null
1729
   //     { else if ( cond_predicate ) statement_or_null }
1730
   //     [ else statement_or_null ]
1731

1732
   BEGIN("conditional statement");
122✔
1733

1734
   vlog_node_t v = vlog_new(V_IF);
122✔
1735

1736
   consume(tIF);
122✔
1737
   consume(tLPAREN);
122✔
1738

1739
   vlog_node_t c0 = vlog_new(V_COND);
122✔
1740
   vlog_set_value(c0, p_cond_predicate());
122✔
1741
   vlog_add_cond(v, c0);
122✔
1742

1743
   consume(tRPAREN);
122✔
1744

1745
   vlog_node_t s0 = p_statement_or_null();
122✔
1746
   if (s0 != NULL)
122✔
1747
      vlog_add_stmt(c0, s0);
117✔
1748

1749
   bool stop = false;
1750
   while (!stop && optional(tELSE)) {
163✔
1751
      vlog_node_t c = vlog_new(V_COND);
41✔
1752
      vlog_add_cond(v, c);
41✔
1753

1754
      if (optional(tIF)) {
41✔
1755
         consume(tLPAREN);
4✔
1756
         vlog_set_value(c, p_cond_predicate());
4✔
1757
         consume(tRPAREN);
4✔
1758
      }
1759
      else
1760
         stop = true;
1761

1762
      vlog_node_t s = p_statement_or_null();
41✔
1763
      if (s != NULL)
41✔
1764
         vlog_add_stmt(c, s);
40✔
1765
   }
1766

1767
   vlog_set_loc(v, CURRENT_LOC);
122✔
1768
   return v;
122✔
1769
}
1770

1771
static vlog_node_t p_variable_assignment(vlog_kind_t kind)
1✔
1772
{
1773
   // variable_lvalue = expression
1774

1775
   BEGIN("variable assignment");
1✔
1776

1777
   vlog_node_t v = vlog_new(kind);
1✔
1778
   vlog_set_target(v, p_variable_lvalue());
1✔
1779

1780
   consume(tEQ);
1✔
1781

1782
   vlog_set_value(v, p_expression());
1✔
1783

1784
   vlog_set_loc(v, CURRENT_LOC);
1✔
1785
   return v;
1✔
1786
}
1787

1788
static void p_list_of_variable_assignments(vlog_node_t parent)
1✔
1789
{
1790
   // variable_assignment { , variable_assignment }
1791

1792
   BEGIN("list of variable assignments");
2✔
1793

1794
   do {
1✔
1795
      vlog_node_t v = p_variable_assignment(V_BASSIGN);
1✔
1796
      vlog_add_stmt(parent, v);
1✔
1797
   } while (optional(tCOMMA));
1✔
1798
}
1✔
1799

1800
static void p_for_variable_declaration(vlog_node_t parent)
2✔
1801
{
1802
   // [ var ] data_type variable_identifier = expression
1803
   //   { , variable_identifier = expression }
1804

1805
   BEGIN("for variable declaration");
4✔
1806

1807
   optional(tVAR);
2✔
1808

1809
   vlog_node_t dt = p_data_type();
2✔
1810

1811
   do {
2✔
1812
      vlog_node_t v = vlog_new(V_VAR_DECL);
2✔
1813
      vlog_set_ident(v, p_identifier());
2✔
1814
      vlog_set_type(v, dt);
2✔
1815

1816
      consume(tEQ);
2✔
1817

1818
      vlog_set_value(v, p_expression());
2✔
1819

1820
      vlog_set_loc(v, CURRENT_LOC);
2✔
1821
      vlog_add_decl(parent, v);
2✔
1822
   } while (optional(tCOMMA));
2✔
1823
}
2✔
1824

1825
static vlog_node_t p_for_initialization(void)
3✔
1826
{
1827
   // list_of_variable_assignments
1828
   //   | for_variable_declaration { , for_variable_declaration }
1829

1830
   BEGIN("for initialization");
3✔
1831

1832
   vlog_node_t v = vlog_new(V_FOR_INIT);
3✔
1833

1834
   if (scan(tREG, tSTRUCT, tUNION, tENUM, tSVINT, tINTEGER, tSVREAL,
3✔
1835
            tSHORTREAL, tREALTIME, tLOGIC, tVAR)) {
1836
      do {
2✔
1837
         p_for_variable_declaration(v);
2✔
1838
      } while (optional(tCOMMA));
2✔
1839
   }
1840
   else
1841
      p_list_of_variable_assignments(v);
1✔
1842

1843
   vlog_set_loc(v, CURRENT_LOC);
3✔
1844
   return v;
3✔
1845
}
1846

1847
static vlog_node_t p_for_step(void)
3✔
1848
{
1849
   // operator_assignment | inc_or_dec_expression | function_subroutine_call
1850

1851
   BEGIN("for step");
3✔
1852

1853
   vlog_node_t v = vlog_new(V_FOR_STEP);
3✔
1854

1855
   switch (peek()) {
3✔
1856
   case tPLUSPLUS:
1✔
1857
   case tMINUSMINUS:
1858
      vlog_add_stmt(v, p_inc_or_dec_expression(NULL));
1✔
1859
      break;
1✔
1860
   default:
2✔
1861
      {
1862
         vlog_node_t head = p_variable_lvalue();
2✔
1863

1864
         switch (peek()) {
2✔
1865
         case tPLUSPLUS:
1✔
1866
         case tMINUSMINUS:
1867
            vlog_add_stmt(v, p_inc_or_dec_expression(head));
1✔
1868
            break;
1✔
1869
         default:
1✔
1870
            vlog_add_stmt(v, p_operator_assignment(head));
1✔
1871
            break;
1✔
1872
         }
1873
      }
1874
      break;
1875
   }
1876

1877
   vlog_set_loc(v, CURRENT_LOC);
3✔
1878
   return v;
3✔
1879
}
1880

1881
static vlog_node_t p_loop_statement(void)
13✔
1882
{
1883
   // forever statement_or_null
1884
   //   | repeat ( expression ) statement_or_null
1885
   //   | while ( expression ) statement_or_null
1886
   //   | for ( [ for_initialization ] ; [ expression ] ; [ for_step ] )
1887
   //       statement_or_null
1888
   //   | do statement_or_null while ( expression ) ;
1889
   //   | foreach ( ps_or_hierarchical_array_identifier [ loop_variables ] )
1890
   //       statement
1891

1892
   BEGIN("loop statement");
26✔
1893

1894
   switch (one_of(tFOREVER, tWHILE, tREPEAT, tDO, tFOR)) {
13✔
1895
   case tFOREVER:
3✔
1896
      {
1897
         vlog_node_t v = vlog_new(V_FOREVER);
3✔
1898

1899
         vlog_node_t s = p_statement_or_null();
3✔
1900
         if (s != NULL)
3✔
1901
            vlog_add_stmt(v, s);
3✔
1902

1903
         vlog_set_loc(v, CURRENT_LOC);
3✔
1904
         return v;
3✔
1905
      }
1906

1907
   case tWHILE:
2✔
1908
      {
1909
         vlog_node_t v = vlog_new(V_WHILE);
2✔
1910

1911
         consume(tLPAREN);
2✔
1912
         vlog_set_value(v, p_expression());
2✔
1913
         consume(tRPAREN);
2✔
1914

1915
         vlog_node_t s = p_statement_or_null();
2✔
1916
         if (s != NULL)
2✔
1917
            vlog_add_stmt(v, s);
×
1918

1919
         vlog_set_loc(v, CURRENT_LOC);
2✔
1920
         return v;
2✔
1921
      }
1922

1923
   case tREPEAT:
2✔
1924
      {
1925
         vlog_node_t v = vlog_new(V_REPEAT);
2✔
1926

1927
         consume(tLPAREN);
2✔
1928
         vlog_set_value(v, p_expression());
2✔
1929
         consume(tRPAREN);
2✔
1930

1931
         vlog_node_t s = p_statement_or_null();
2✔
1932
         if (s != NULL)
2✔
1933
            vlog_add_stmt(v, s);
2✔
1934

1935
         vlog_set_loc(v, CURRENT_LOC);
2✔
1936
         return v;
2✔
1937
      }
1938

1939
   case tDO:
2✔
1940
      {
1941
         vlog_node_t v = vlog_new(V_DO_WHILE);
2✔
1942

1943
         vlog_node_t s = p_statement_or_null();
2✔
1944
         if (s != NULL)
2✔
1945
            vlog_add_stmt(v, s);
2✔
1946

1947
         consume(tWHILE);
2✔
1948

1949
         consume(tLPAREN);
2✔
1950
         vlog_set_value(v, p_expression());
2✔
1951
         consume(tRPAREN);
2✔
1952
         consume(tSEMI);
2✔
1953

1954
         vlog_set_loc(v, CURRENT_LOC);
2✔
1955
         return v;
2✔
1956
      }
1957

1958
   case tFOR:
4✔
1959
      {
1960
         vlog_node_t v = vlog_new(V_FOR_LOOP);
4✔
1961

1962
         consume(tLPAREN);
4✔
1963

1964
         if (not_at_token(tSEMI))
4✔
1965
            vlog_set_left(v, p_for_initialization());
3✔
1966
         else
1967
            vlog_set_left(v, vlog_new(V_FOR_INIT));
1✔
1968

1969
         consume(tSEMI);
4✔
1970

1971
         if (not_at_token(tSEMI))
4✔
1972
            vlog_set_value(v, p_expression());
2✔
1973

1974
         consume(tSEMI);
4✔
1975

1976
         if (not_at_token(tRPAREN))
4✔
1977
            vlog_set_right(v, p_for_step());
3✔
1978
         else
1979
            vlog_set_right(v, vlog_new(V_FOR_STEP));
1✔
1980

1981
         consume(tRPAREN);
4✔
1982

1983
         vlog_node_t s = p_statement_or_null();
4✔
1984
         if (s != NULL)
4✔
1985
            vlog_add_stmt(v, s);
1✔
1986

1987
         vlog_set_loc(v, CURRENT_LOC);
4✔
1988
         return v;
4✔
1989
      }
1990

1991
   default:
×
1992
      should_not_reach_here();
1993
   }
1994
}
1995

1996
static vlog_node_t p_wait_statement(void)
1✔
1997
{
1998
   // wait ( expression ) statement_or_null
1999
   //   | wait fork ;
2000
   //   | wait_order ( hierarchical_identifier { , hierarchical_identifier } )
2001
   //       action_block
2002

2003
   BEGIN("wait statement");
1✔
2004

2005
   consume(tWAIT);
1✔
2006

2007
   vlog_node_t v = vlog_new(V_WAIT);
1✔
2008

2009
   consume(tLPAREN);
1✔
2010

2011
   vlog_set_value(v, p_expression());
1✔
2012

2013
   consume(tRPAREN);
1✔
2014

2015
   vlog_node_t s = p_statement_or_null();
1✔
2016
   if (s != NULL)
1✔
2017
      vlog_add_stmt(v, s);
1✔
2018

2019
   vlog_set_loc(v, CURRENT_LOC);
1✔
2020
   return v;
1✔
2021
}
2022

2023
static vlog_node_t p_statement_item(void)
1,214✔
2024
{
2025
   // blocking_assignment ; | nonblocking_assignment ;
2026
   //   | procedural_continuous_assignment ; | case_statement
2027
   //   | conditional_statement | inc_or_dec_expression ;
2028
   //   | subroutine_call_statement | disable_statement
2029
   //   | event_trigger | loop_statement | jump_statement
2030
   //   | par_block | procedural_timing_control_statement
2031
   //   | seq_block | wait_statement | procedural_assertion_statement
2032
   //   | clocking_drive ; | randsequence_statement | randcase_statement
2033
   //   | expect_property_statement
2034

2035
   BEGIN("statement item");
2,428✔
2036

2037
   switch (peek()) {
1,214✔
2038
   case tID:
286✔
2039
      {
2040
         vlog_node_t lhs = p_variable_lvalue(), v = NULL;
286✔
2041

2042
         if (peek() == tLE)
286✔
2043
            v = p_nonblocking_assignment(lhs);
82✔
2044
         else
2045
            v = p_blocking_assignment(lhs);
204✔
2046

2047
         consume(tSEMI);
286✔
2048
         return v;
286✔
2049
      }
2050
   case tAT:
215✔
2051
   case tHASH:
2052
      return p_procedural_timing_control_statement();
215✔
2053
   case tBEGIN:
187✔
2054
      return p_seq_block();
187✔
2055
   case tSYSTASK:
390✔
2056
      return p_subroutine_call_statement();
390✔
2057
   case tIF:
122✔
2058
      return p_conditional_statement();
122✔
2059
   case tFOREVER:
13✔
2060
   case tWHILE:
2061
   case tREPEAT:
2062
   case tDO:
2063
   case tFOR:
2064
      return p_loop_statement();
13✔
2065
   case tWAIT:
1✔
2066
      return p_wait_statement();
1✔
2067
   default:
×
2068
      one_of(tID, tAT, tHASH, tBEGIN, tSYSTASK, tIF, tFOREVER, tWHILE, tREPEAT,
×
2069
             tDO, tFOR, tWAIT);
2070
      drop_tokens_until(tSEMI);
×
2071
      return NULL;
×
2072
   }
2073
}
2074

2075
static vlog_node_t p_statement(void)
1,214✔
2076
{
2077
   // [ block_identifier : ] { attribute_instance } statement_item
2078

2079
   BEGIN("statement");
2,428✔
2080

2081
   while (peek() == tATTRBEGIN)
1,214✔
2082
      p_attribute_instance();
×
2083

2084
   vlog_node_t s = p_statement_item();
1,214✔
2085
   if (s == NULL)
1,214✔
2086
      return vlog_new(V_SEQ_BLOCK);
×
2087

2088
   return s;
2089
}
2090

2091
static vlog_node_t p_statement_or_null(void)
1,230✔
2092
{
2093
   // statement | { attribute_instance } ;
2094

2095
   BEGIN("statement or null");
2,460✔
2096

2097
   if (optional(tSEMI))
1,230✔
2098
      return NULL;
2099
   else
2100
      return p_statement();
1,138✔
2101
}
2102

2103
static vlog_node_t p_always_construct(void)
76✔
2104
{
2105
   // always_keyword statement
2106

2107
   BEGIN("always construct");
76✔
2108

2109
   vlog_node_t v = vlog_new(V_ALWAYS);
76✔
2110

2111
   switch (one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH)) {
76✔
2112
   case tALWAYSCOMB:  vlog_set_subkind(v, V_ALWAYS_COMB);  break;
1✔
2113
   case tALWAYSFF:    vlog_set_subkind(v, V_ALWAYS_FF);    break;
1✔
2114
   case tALWAYSLATCH: vlog_set_subkind(v, V_ALWAYS_LATCH); break;
1✔
2115
   default:           vlog_set_subkind(v, V_ALWAYS_PLAIN); break;
73✔
2116
   }
2117

2118
   vlog_set_ident(v, ident_uniq("__always#line%d", yylloc.first_line));
76✔
2119
   vlog_add_stmt(v, p_statement());
76✔
2120

2121
   vlog_set_loc(v, CURRENT_LOC);
76✔
2122
   return v;
76✔
2123
}
2124

2125
static vlog_node_t p_initial_construct(void)
74✔
2126
{
2127
   // initial statement_or_null
2128

2129
   BEGIN("initial construct");
74✔
2130

2131
   consume(tINITIAL);
74✔
2132

2133
   vlog_node_t v = vlog_new(V_INITIAL);
74✔
2134
   vlog_set_ident(v, ident_uniq("__initial#line%d", yylloc.first_line));
74✔
2135

2136
   vlog_node_t s = p_statement_or_null();
74✔
2137
   if (s != NULL)
74✔
2138
      vlog_add_stmt(v, s);
74✔
2139

2140
   vlog_set_loc(v, CURRENT_LOC);
74✔
2141
   return v;
74✔
2142
}
2143

2144
static vlog_node_t p_net_assignment(void)
51✔
2145
{
2146
   // net_lvalue = expression
2147

2148
   BEGIN("net assignment");
51✔
2149

2150
   vlog_node_t v = vlog_new(V_ASSIGN);
51✔
2151
   vlog_set_target(v, p_net_lvalue());
51✔
2152
   vlog_set_ident(v, ident_uniq("__assign#line%d", state.last_loc.first_line));
51✔
2153

2154
   consume(tEQ);
51✔
2155

2156
   vlog_set_value(v, p_expression());
51✔
2157

2158
   vlog_set_loc(v, CURRENT_LOC);
51✔
2159
   return v;
51✔
2160
}
2161

2162
static void p_list_of_net_assignments(vlog_node_t mod)
51✔
2163
{
2164
   // net_assignment { , net_assignment }
2165

2166
   BEGIN("list of net assignments");
102✔
2167

2168
   do {
51✔
2169
      vlog_add_stmt(mod, p_net_assignment());
51✔
2170
   } while (optional(tCOMMA));
51✔
2171
}
51✔
2172

2173
static void p_continuous_assign(vlog_node_t mod)
51✔
2174
{
2175
   // assign [ drive_strength ] [ delay3 ] list_of_net_assignments ;
2176
   //   | assign [ delay_control ] list_of_variable_assignments ;
2177

2178
   BEGIN("continuous assignment");
102✔
2179

2180
   consume(tASSIGN);
51✔
2181

2182
   p_list_of_net_assignments(mod);
51✔
2183

2184
   consume(tSEMI);
51✔
2185
}
51✔
2186

2187
static vlog_net_kind_t p_net_type(void)
80✔
2188
{
2189
   // supply0 | supply1 | tri | triand | trior | trireg | tri0
2190
   //   | tri1 | uwire | wire | wand | wor
2191

2192
   BEGIN("net type");
160✔
2193

2194
   switch (one_of(tWIRE, tSUPPLY0, tSUPPLY1)) {
80✔
2195
   case tSUPPLY0: return V_NET_SUPPLY0;
2196
   case tSUPPLY1: return V_NET_SUPPLY1;
3✔
2197
   case tWIRE:
71✔
2198
   default: return V_NET_WIRE;
71✔
2199
   }
2200
}
2201

2202
static vlog_node_t p_net_decl_assignment(vlog_net_kind_t kind,
98✔
2203
                                         vlog_node_t datatype)
2204
{
2205
   // net_identifier { unpacked_dimension } [ = expression ]
2206

2207
   BEGIN("net declaration assignment");
98✔
2208

2209
   vlog_node_t v = vlog_new(V_NET_DECL);
98✔
2210
   vlog_set_subkind(v, kind);
98✔
2211
   vlog_set_type(v, datatype);
98✔
2212
   vlog_set_ident(v, p_identifier());
98✔
2213

2214
   while (peek() == tLSQUARE)
99✔
2215
      vlog_add_range(v, p_unpacked_dimension());
1✔
2216

2217
   if (optional(tEQ))
98✔
2218
      vlog_set_value(v, p_expression());
10✔
2219

2220
   vlog_set_loc(v, CURRENT_LOC);
98✔
2221
   return v;
98✔
2222
}
2223

2224
static void p_list_of_net_decl_assignments(vlog_node_t mod,
80✔
2225
                                           vlog_net_kind_t kind,
2226
                                           vlog_node_t datatype)
2227
{
2228
   // net_decl_assignment { , net_decl_assignment }
2229

2230
   BEGIN("list of net declaration assignments");
160✔
2231

2232
   do {
98✔
2233
      vlog_node_t v = p_net_decl_assignment(kind, datatype);
98✔
2234
      vlog_add_decl(mod, v);
98✔
2235
   } while (optional(tCOMMA));
98✔
2236
}
80✔
2237

2238
static void p_net_declaration(vlog_node_t mod)
80✔
2239
{
2240
   // net_type [ drive_strength | charge_strength ] [ vectored | scalared ]
2241
   //     data_type_or_implicit [ delay3 ] list_of_net_decl_assignments ;
2242
   //  | net_type_identifier [ delay_control ] list_of_net_decl_assignments ;
2243
   //  | interconnect implicit_data_type [ # delay_value ] net_identifier
2244
   //     { unpacked_dimension } [ , net_identifier { unpacked_dimension } ] ;
2245

2246
   BEGIN("net declaration");
160✔
2247

2248
   const vlog_net_kind_t kind = p_net_type();
80✔
2249

2250
   vlog_node_t dt = p_data_type_or_implicit();
80✔
2251
   p_list_of_net_decl_assignments(mod, kind, dt);
80✔
2252

2253
   consume(tSEMI);
80✔
2254
}
80✔
2255

2256
static vlog_node_t p_variable_dimension(void)
2✔
2257
{
2258
   // unsized_dimension | unpacked_dimension | associative_dimension
2259
   //   | queue_dimension
2260

2261
   BEGIN("variable dimension");
4✔
2262

2263
   return p_unpacked_dimension();
2✔
2264
}
2265

2266
static vlog_node_t p_variable_decl_assignment(vlog_node_t datatype)
149✔
2267
{
2268
   // variable_identifier { variable_dimension } [ = expression ]
2269
   //   | dynamic_array_variable_identifier unsized_dimension
2270
   //       { variable_dimension } [ = dynamic_array_new ]
2271
   //   | class_variable_identifier [ = class_new ]
2272

2273
   BEGIN("variable declaration assignment");
149✔
2274

2275
   vlog_node_t v = vlog_new(V_VAR_DECL);
149✔
2276
   vlog_set_ident(v, p_identifier());
149✔
2277
   vlog_set_type(v, datatype);
149✔
2278

2279
   while (peek() == tLSQUARE)
151✔
2280
      vlog_add_range(v, p_variable_dimension());
2✔
2281

2282
   if (optional(tEQ))
149✔
2283
      vlog_set_value(v, p_expression());
7✔
2284

2285
   vlog_set_loc(v, CURRENT_LOC);
149✔
2286
   return v;
149✔
2287
}
2288

2289
static void p_list_of_variable_decl_assignments(vlog_node_t parent,
127✔
2290
                                                vlog_node_t datatype)
2291
{
2292
   // variable_decl_assignment { , variable_decl_assignment }
2293

2294
   BEGIN("list of variable declaration assignments");
254✔
2295

2296
   do {
149✔
2297
      vlog_add_decl(parent, p_variable_decl_assignment(datatype));
149✔
2298
   } while (optional(tCOMMA));
149✔
2299
}
127✔
2300

2301
static vlog_node_t p_type_declaration(void)
3✔
2302
{
2303
   // typedef data_type type_identifier { variable_dimension } ;
2304
   //   | typedef interface_instance_identifier constant_bit_select .
2305
   //       type_identifier type_identifier ;
2306
   //   | typedef [ enum | struct | union | class | interface class ]
2307
   //       type_identifier ;
2308

2309
   BEGIN("type declaration");
3✔
2310

2311
   consume(tTYPEDEF);
3✔
2312

2313
   vlog_node_t v = vlog_new(V_TYPE_DECL);
3✔
2314
   vlog_set_type(v, p_data_type());
3✔
2315
   vlog_set_ident(v, p_identifier());
3✔
2316

2317
   consume(tSEMI);
3✔
2318

2319
   vlog_set_loc(v, CURRENT_LOC);
3✔
2320
   return v;
3✔
2321
}
2322

2323
static void p_data_declaration(vlog_node_t mod)
121✔
2324
{
2325
   // [ const ] [ var ] [ lifetime ] data_type_or_implicit
2326
   //     list_of_variable_decl_assignments ;
2327
   //  | type_declaration | package_import_declaration | net_type_declaration
2328

2329
   BEGIN("data declaration");
242✔
2330

2331
   switch (peek()) {
121✔
2332
   case tTYPEDEF:
3✔
2333
      vlog_add_decl(mod, p_type_declaration());
3✔
2334
      break;
3✔
2335

2336
   default:
118✔
2337
      {
2338
         vlog_node_t dt = p_data_type_or_implicit();
118✔
2339
         p_list_of_variable_decl_assignments(mod, dt);
118✔
2340

2341
         consume(tSEMI);
118✔
2342
      }
2343
   }
2344
}
121✔
2345

2346
static v_port_kind_t p_port_direction(void)
3✔
2347
{
2348
   // input | output | inout | ref
2349

2350
   BEGIN("port direction");
6✔
2351

2352
   switch (one_of(tINPUT, tOUTPUT, tINOUT)) {
3✔
2353
   case tINPUT:  return V_PORT_INPUT;
2354
   case tOUTPUT: return V_PORT_OUTPUT;
1✔
2355
   case tINOUT:  return V_PORT_INOUT;
×
2356
   default:      return V_PORT_INPUT;
2357
   }
2358
}
2359

2360
static v_port_kind_t p_tf_port_direction(void)
3✔
2361
{
2362
   // port_direction | const ref
2363

2364
   BEGIN("task or function port direction");
6✔
2365

2366
   return p_port_direction();
3✔
2367
}
2368

2369
static vlog_node_t p_tf_port_item(void)
4✔
2370
{
2371
   // { attribute_instance } [ tf_port_direction ] [ var ]
2372
   //    data_type_or_implicit [ port_identifier { variable_dimension }
2373
   //    [ = expression ] ]
2374

2375
   BEGIN("task or function port item");
4✔
2376

2377
   vlog_node_t v = vlog_new(V_PORT_DECL);
4✔
2378

2379
   if (scan(tINPUT, tOUTPUT))
4✔
2380
      vlog_set_subkind(v, p_tf_port_direction());
3✔
2381
   else
2382
      vlog_set_subkind(v, V_PORT_INPUT);
1✔
2383

2384
   vlog_set_type(v, p_data_type_or_implicit());
4✔
2385

2386
   if (peek() == tID) {
4✔
2387
      vlog_set_ident(v, p_identifier());
4✔
2388

2389
      if (optional(tEQ))
4✔
2390
         vlog_set_value(v, p_expression());
×
2391
   }
2392

2393
   vlog_set_loc(v, CURRENT_LOC);
4✔
2394
   return v;
4✔
2395
}
2396

2397
static void p_tf_port_list(vlog_node_t tf)
2✔
2398
{
2399
   // tf_port_item { , tf_port_item }
2400

2401
   BEGIN("task or function port list");
4✔
2402

2403
   do {
4✔
2404
      p_tf_port_item();
4✔
2405
   } while (optional(tCOMMA));
4✔
2406
}
2✔
2407

2408
static void p_task_body_declaration(vlog_node_t task)
2✔
2409
{
2410
   // [ interface_identifier . | class_scope ] task_identifier ;
2411
   //    { tf_item_declaration } { statement_or_null }
2412
   //    endtask [ : task_identifier ]
2413
   // | [ interface_identifier . | class_scope ] task_identifier
2414
   //    ( [ tf_port_list ] ) ; { block_item_declaration }
2415
   //    { statement_or_null } endtask [ : task_identifier ]
2416

2417
   BEGIN("task body declaration");
4✔
2418

2419
   ident_t id = p_identifier();
2✔
2420
   vlog_set_ident(task, id);
2✔
2421

2422
   if (optional(tLPAREN)) {
2✔
2423
      p_tf_port_list(task);
1✔
2424
      consume(tRPAREN);
1✔
2425
   }
2426

2427
   consume(tSEMI);
2✔
2428

2429
   while (not_at_token(tENDTASK)) {
6✔
2430
      vlog_node_t s = p_statement_or_null();
2✔
2431
      if (s != NULL)
2✔
2432
         vlog_add_stmt(task, s);
2✔
2433
   }
2434

2435
   consume(tENDTASK);
2✔
2436
}
2✔
2437

2438
static vlog_node_t p_task_declaration(void)
2✔
2439
{
2440
   // task [ dynamic_override_specifiers ] [ lifetime ] task_body_declaration
2441

2442
   BEGIN("task declaration");
2✔
2443

2444
   vlog_node_t v = vlog_new(V_TASK_DECL);
2✔
2445

2446
   consume(tTASK);
2✔
2447

2448
   p_task_body_declaration(v);
2✔
2449

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

2454
static vlog_node_t p_function_data_type_or_implicit(void)
1✔
2455
{
2456
   // data_type_or_void | implicit_data_type
2457

2458
   BEGIN("function data type or implicit");
2✔
2459

2460
   return p_implicit_data_type();
1✔
2461
}
2462

2463
static void p_function_body_declaration(vlog_node_t func)
1✔
2464
{
2465
   // function_data_type_or_implicit [ interface_identifier . | class_scope ]
2466
   //    function_identifier ; { tf_item_declaration }
2467
   //    { function_statement_or_null } endfunction [ : function_identifier ]
2468
   // | function_data_type_or_implicit [ interface_identifier . | class_scope ]
2469
   //    function_identifier ( [ tf_port_list ] ) ; { block_item_declaration }
2470
   //    { function_statement_or_null } endfunction [ : function_identifier ]
2471

2472
   BEGIN("function body declaration");
2✔
2473

2474
   vlog_set_type(func, p_function_data_type_or_implicit());
1✔
2475

2476
   ident_t id = p_identifier();
1✔
2477
   vlog_set_ident(func, id);
1✔
2478

2479
   if (optional(tLPAREN)) {
1✔
2480
      p_tf_port_list(func);
1✔
2481
      consume(tRPAREN);
1✔
2482
   }
2483

2484
   consume(tSEMI);
1✔
2485

2486
   while (not_at_token(tENDFUNCTION)) {
3✔
2487
      vlog_node_t s = p_statement_or_null();
1✔
2488
      if (s != NULL)
1✔
2489
         vlog_add_stmt(func, s);
1✔
2490
   }
2491

2492
   consume(tENDFUNCTION);
1✔
2493
}
1✔
2494

2495
static vlog_node_t p_function_declaration(void)
1✔
2496
{
2497
   // function [ lifetime ] function_body_declaration
2498

2499
   BEGIN("function declaration");
1✔
2500

2501
   vlog_node_t v = vlog_new(V_FUNC_DECL);
1✔
2502

2503
   consume(tFUNCTION);
1✔
2504

2505
   p_function_body_declaration(v);
1✔
2506

2507
   vlog_set_loc(v, CURRENT_LOC);
1✔
2508
   return v;
1✔
2509
}
2510

2511
static vlog_node_t p_constant_param_expression(void)
9✔
2512
{
2513
   // mintypmax_expression | data_type | $
2514

2515
   BEGIN("constant parameter expression");
18✔
2516

2517
   return p_mintypmax_expression();
9✔
2518
}
2519

2520
static vlog_node_t p_param_assignment(vlog_node_t datatype, vlog_kind_t kind)
9✔
2521
{
2522
   // parameter_identifier { unpacked_dimension }
2523
   //   [ = constant_param_expression ]
2524

2525
   BEGIN("parameter assignment");
9✔
2526

2527
   vlog_node_t v = vlog_new(kind);
9✔
2528
   vlog_set_ident(v, p_identifier());
9✔
2529
   vlog_set_type(v, datatype);
9✔
2530

2531
   if (optional(tEQ))
9✔
2532
      vlog_set_value(v, p_constant_param_expression());
9✔
2533

2534
   vlog_set_loc(v, CURRENT_LOC);
9✔
2535
   return v;
9✔
2536
}
2537

2538
static void p_list_of_param_assignments(vlog_node_t parent,
9✔
2539
                                        vlog_node_t datatype,
2540
                                        vlog_kind_t kind)
2541
{
2542
   // param_assignment { , param_assignment }
2543

2544
   BEGIN("list of parameter assignments");
18✔
2545

2546
   do {
9✔
2547
      vlog_add_decl(parent, p_param_assignment(datatype, kind));
9✔
2548
   } while (optional(tCOMMA));
9✔
2549
}
9✔
2550

2551
static void p_parameter_declaration(vlog_node_t mod)
5✔
2552
{
2553
   // parameter data_type_or_implicit list_of_param_assignments
2554

2555
   BEGIN("parameter declaration");
10✔
2556

2557
   consume(tPARAMETER);
5✔
2558

2559
   vlog_node_t dt = p_data_type_or_implicit();
5✔
2560
   p_list_of_param_assignments(mod, dt, V_PARAM_DECL);
5✔
2561
}
5✔
2562

2563
static void p_local_parameter_declaration(vlog_node_t mod)
4✔
2564
{
2565
   // localparam data_type_or_implicit list_of_param_assignments
2566

2567
   BEGIN("local parameter declaration");
8✔
2568

2569
   consume(tLOCALPARAM);
4✔
2570

2571
   vlog_node_t dt = p_data_type_or_implicit();
4✔
2572
   p_list_of_param_assignments(mod, dt, V_LOCALPARAM);
4✔
2573
}
4✔
2574

2575
static void p_package_or_generate_item_declaration(vlog_node_t mod)
213✔
2576
{
2577
   // net_declaration | data_declaration | task_declaration
2578
   //   | function_declaration | checker_declaration | dpi_import_export
2579
   //   | extern_constraint_declaration | class_declaration
2580
   //   | class_constructor_declaration | local_parameter_declaration ;
2581
   //   | parameter_declaration ; | covergroup_declaration
2582
   //   | overload_declaration | assertion_item_declaration | ;
2583

2584
   BEGIN("package or generate item declaration");
426✔
2585

2586
   switch (peek()) {
213✔
2587
   case tWIRE:
80✔
2588
   case tSUPPLY0:
2589
   case tSUPPLY1:
2590
      p_net_declaration(mod);
80✔
2591
      break;
80✔
2592
   case tREG:
121✔
2593
   case tSTRUCT:
2594
   case tUNION:
2595
   case tTYPEDEF:
2596
   case tENUM:
2597
   case tSVINT:
2598
   case tINTEGER:
2599
   case tSVREAL:
2600
   case tSHORTREAL:
2601
   case tREALTIME:
2602
      p_data_declaration(mod);
121✔
2603
      break;
121✔
2604
   case tTASK:
2✔
2605
      vlog_add_decl(mod, p_task_declaration());
2✔
2606
      break;
2✔
2607
   case tFUNCTION:
1✔
2608
      vlog_add_decl(mod, p_function_declaration());
1✔
2609
      break;
1✔
2610
   case tLOCALPARAM:
4✔
2611
      p_local_parameter_declaration(mod);
4✔
2612
      consume(tSEMI);
4✔
2613
      break;
4✔
2614
   case tPARAMETER:
5✔
2615
      p_parameter_declaration(mod);
5✔
2616
      consume(tSEMI);
5✔
2617
      break;
5✔
2618
   default:
×
2619
      one_of(tWIRE, tSUPPLY0, tSUPPLY1, tREG, tSTRUCT, tUNION, tTYPEDEF,
×
2620
             tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTASK,
2621
             tFUNCTION, tLOCALPARAM, tPARAMETER);
2622
      drop_tokens_until(tSEMI);
×
2623
      break;
×
2624
   }
2625
}
213✔
2626

2627
static void p_module_or_generate_item_declaration(vlog_node_t mod)
213✔
2628
{
2629
   // package_or_generate_item_declaration | genvar_declaration
2630
   //   | clocking_declaration | default clocking clocking_identifier ;
2631
   //   | default disable iff expression_or_dist ;
2632

2633
   BEGIN("module or generate item declaration");
426✔
2634

2635
   p_package_or_generate_item_declaration(mod);
213✔
2636
}
213✔
2637

2638
static void p_module_common_item(vlog_node_t mod)
414✔
2639
{
2640
   // module_or_generate_item_declaration
2641
   //   | interface_instantiation | program_instantiation
2642
   //   | assertion_item | bind_directive | continuous_assign
2643
   //   | net_alias | initial_construct | final_construct
2644
   //   | always_construct | loop_generate_construct
2645
   //   | conditional_generate_construct | elaboration_system_task
2646

2647
   BEGIN("module common item");
828✔
2648

2649
   switch (peek()) {
414✔
2650
   case tALWAYS:
76✔
2651
   case tALWAYSCOMB:
2652
   case tALWAYSFF:
2653
   case tALWAYSLATCH:
2654
      vlog_add_stmt(mod, p_always_construct());
76✔
2655
      break;
76✔
2656
   case tINITIAL:
74✔
2657
      vlog_add_stmt(mod, p_initial_construct());
74✔
2658
      break;
74✔
2659
   case tWIRE:
213✔
2660
   case tSUPPLY0:
2661
   case tSUPPLY1:
2662
   case tREG:
2663
   case tSTRUCT:
2664
   case tUNION:
2665
   case tTYPEDEF:
2666
   case tENUM:
2667
   case tSVINT:
2668
   case tINTEGER:
2669
   case tSVREAL:
2670
   case tSHORTREAL:
2671
   case tREALTIME:
2672
   case tTASK:
2673
   case tFUNCTION:
2674
   case tLOCALPARAM:
2675
   case tPARAMETER:
2676
      p_module_or_generate_item_declaration(mod);
213✔
2677
      break;
213✔
2678
   case tASSIGN:
51✔
2679
      p_continuous_assign(mod);
51✔
2680
      break;
51✔
2681
   default:
×
NEW
2682
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tSUPPLY0,
×
2683
             tSUPPLY1, tREG, tSTRUCT, tUNION, tTYPEDEF, tENUM, tSVINT,
2684
             tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTASK, tFUNCTION,
2685
             tPARAMETER, tLOCALPARAM, tASSIGN);
UNCOV
2686
      drop_tokens_until(tSEMI);
×
2687
   }
2688
}
414✔
2689

2690
static vlog_strength_t p_strength0(void)
4✔
2691
{
2692
   // supply0 | strong0 | pull0 | weak0
2693

2694
   BEGIN("strength0");
4✔
2695

2696
   switch (one_of(tSUPPLY0)) {
4✔
2697
   default:
2698
   case tSUPPLY0: return V_STRENGTH_SUPPLY;
4✔
2699
   }
2700
}
2701

2702
static vlog_strength_t p_strength1(void)
6✔
2703
{
2704
   // supply1 | strong1 | pull1 | weak1
2705

2706
   BEGIN("strength1");
6✔
2707

2708
   switch (one_of(tSUPPLY1)) {
6✔
2709
   default:
2710
   case tSUPPLY1: return V_STRENGTH_SUPPLY;
6✔
2711
   }
2712
}
2713

2714
static vlog_node_t p_pulldown_strength(void)
2✔
2715
{
2716
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength0 )
2717

2718
   BEGIN("pulldown strength");
2✔
2719

2720
   consume(tLPAREN);
2✔
2721

2722
   vlog_strength_t s0, s1;
2✔
2723
   switch (peek()) {
2✔
2724
   case tSUPPLY1:
×
2725
      s1 = p_strength1();
×
2726
      consume(tCOMMA);
×
2727
      s0 = p_strength0();
×
2728
      break;
×
2729
   default:
2✔
2730
      s0 = s1 = p_strength0();
2✔
2731
      if (optional(tCOMMA))
2✔
2732
         s1 = p_strength1();
×
2733
      break;
2734
   }
2735

2736
   consume(tRPAREN);
2✔
2737

2738
   vlog_node_t v = vlog_new(V_STRENGTH);
2✔
2739
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
2✔
2740
   vlog_set_loc(v, CURRENT_LOC);
2✔
2741
   return v;
2✔
2742
}
2743

2744
static vlog_node_t p_pullup_strength(void)
6✔
2745
{
2746
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength1 )
2747

2748
   BEGIN("pullup strength");
6✔
2749

2750
   consume(tLPAREN);
6✔
2751

2752
   vlog_strength_t s0, s1;
6✔
2753
   switch (peek()) {
6✔
2754
   case tSUPPLY0:
1✔
2755
      s0 = p_strength0();
1✔
2756
      consume(tCOMMA);
1✔
2757
      s1 = p_strength1();
1✔
2758
      break;
1✔
2759
   default:
5✔
2760
      s1 = s0 = p_strength1();
5✔
2761
      if (optional(tCOMMA))
5✔
2762
         s0 = p_strength0();
1✔
2763
      break;
2764
   }
2765

2766
   consume(tRPAREN);
6✔
2767

2768
   vlog_node_t v = vlog_new(V_STRENGTH);
6✔
2769
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
6✔
2770
   vlog_set_loc(v, CURRENT_LOC);
6✔
2771
   return v;
6✔
2772
}
2773

2774
static vlog_node_t p_pull_gate_instance(vlog_gate_kind_t kind, vlog_node_t st)
19✔
2775
{
2776
   // [ name_of_instance ] ( output_terminal )
2777

2778
   BEGIN("pull gate instance");
19✔
2779

2780
   vlog_node_t v = vlog_new(V_GATE_INST);
19✔
2781
   vlog_set_subkind(v, kind);
19✔
2782
   vlog_add_param(v, st);
19✔
2783

2784
   if (peek() == tID)
19✔
2785
      vlog_set_ident(v, p_identifier());
7✔
2786

2787
   consume(tLPAREN);
19✔
2788

2789
   vlog_set_target(v, p_net_lvalue());
19✔
2790

2791
   consume(tRPAREN);
19✔
2792

2793
   vlog_set_loc(v, CURRENT_LOC);
19✔
2794
   return v;
19✔
2795
}
2796

2797
static vlog_node_t p_n_terminal_gate_instance(vlog_gate_kind_t kind)
17✔
2798
{
2799
   // [ name_of_instance ] ( output_terminal , input_terminal
2800
   //     { , input_terminal } )
2801

2802
   BEGIN("N-terminal gate instance");
17✔
2803

2804
   vlog_node_t v = vlog_new(V_GATE_INST);
17✔
2805
   vlog_set_subkind(v, kind);
17✔
2806

2807
   if (peek() == tID)
17✔
2808
      vlog_set_ident(v, p_identifier());
2✔
2809

2810
   consume(tLPAREN);
17✔
2811

2812
   vlog_set_target(v, p_net_lvalue());
17✔
2813

2814
   consume(tCOMMA);
17✔
2815

2816
   do {
30✔
2817
      vlog_add_param(v, p_net_lvalue());
30✔
2818
   } while (optional(tCOMMA));
30✔
2819

2820
   consume(tRPAREN);
17✔
2821

2822
   vlog_set_loc(v, CURRENT_LOC);
17✔
2823
   return v;
17✔
2824
}
2825

2826
static void p_gate_instantiation(vlog_node_t mod)
36✔
2827
{
2828
   // cmos_switchtype [ delay3 ] cmos_switch_instance
2829
   //     { , cmos_switch_instance } ;
2830
   //  | enable_gatetype [ drive_strength ] [ delay3 ]
2831
   //     enable_gate_instance { , enable_gate_instance } ;
2832
   //  | mos_switchtype [ delay3 ] mos_switch_instance
2833
   //     { , mos_switch_instance } ;
2834
   //  | n_input_gatetype [ drive_strength ] [ delay2 ] n_input_gate_instance
2835
   //     { , n_input_gate_instance } ;
2836
   //  | n_output_gatetype [ drive_strength ] [ delay2 ] n_output_gate_instance
2837
   //     { , n_output_gate_instance } ;
2838
   //  | pass_en_switchtype [ delay2 ] pass_enable_switch_instance
2839
   //     { , pass_enable_switch_instance } ;
2840
   //  | pass_switchtype pass_switch_instance { , pass_switch_instance } ;
2841
   //  | pulldown [ pulldown_strength ] pull_gate_instance
2842
   //     { , pull_gate_instance } ;
2843
   //  | pullup [ pullup_strength ] pull_gate_instance
2844
   //     { , pull_gate_instance } ;
2845

2846
   BEGIN("gate instantiation");
72✔
2847

2848
   switch (one_of(tPULLDOWN, tPULLUP, tAND, tNAND, tOR, tNOR, tXOR, tXNOR,
36✔
2849
                  tNOT, tBUF)) {
2850
   case tPULLDOWN:
7✔
2851
      {
2852
         vlog_node_t st;
7✔
2853
         if (peek() == tLPAREN && peek_nth(2) != tID)
7✔
2854
            st = p_pulldown_strength();
2✔
2855
         else {
2856
            st = vlog_new(V_STRENGTH);
5✔
2857
            vlog_set_subkind(st, ST_PULLUP);
5✔
2858
         }
2859

2860
         do {
7✔
2861
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLDOWN, st);
7✔
2862
            vlog_add_stmt(mod, g);
7✔
2863
         } while (optional(tCOMMA));
7✔
2864
      }
2865
      break;
2866

2867
   case tPULLUP:
12✔
2868
      {
2869
         vlog_node_t st;
12✔
2870
         if (peek() == tLPAREN && peek_nth(2) != tID)
12✔
2871
            st = p_pullup_strength();
6✔
2872
         else {
2873
            st = vlog_new(V_STRENGTH);
6✔
2874
            vlog_set_subkind(st, ST_PULLUP);
6✔
2875
         }
2876

2877
         do {
12✔
2878
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLUP, st);
12✔
2879
            vlog_add_stmt(mod, g);
12✔
2880
         } while (optional(tCOMMA));
12✔
2881
      }
2882
      break;
2883

2884
   case tAND:
4✔
2885
      do {
4✔
2886
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_AND));
4✔
2887
      } while (optional(tCOMMA));
4✔
2888
      break;
2889

2890
   case tNAND:
3✔
2891
      do {
3✔
2892
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_NAND));
3✔
2893
      } while (optional(tCOMMA));
3✔
2894
      break;
2895

2896
   case tOR:
4✔
2897
      do {
4✔
2898
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_OR));
4✔
2899
      } while (optional(tCOMMA));
4✔
2900
      break;
2901

2902
   case tNOR:
×
2903
      do {
×
2904
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_NOR));
×
2905
      } while (optional(tCOMMA));
×
2906
      break;
2907

2908
   case tXOR:
3✔
2909
      do {
3✔
2910
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_XOR));
3✔
2911
      } while (optional(tCOMMA));
3✔
2912
      break;
2913

2914
   case tXNOR:
×
2915
      do {
×
2916
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_XNOR));
×
2917
      } while (optional(tCOMMA));
×
2918
      break;
2919

2920
   case tNOT:
3✔
2921
      do {
3✔
2922
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_NOT));
3✔
2923
      } while (optional(tCOMMA));
3✔
2924
      break;
2925

2926
   case tBUF:
×
2927
      do {
×
2928
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_BUF));
×
2929
      } while (optional(tCOMMA));
×
2930
      break;
2931

2932
   default:
2933
      break;
2934
   }
2935

2936
   consume(tSEMI);
36✔
2937
}
36✔
2938

2939
static void p_path_delay_expression(void)
3✔
2940
{
2941
   // constant_expression
2942
   //   | constant_expression : constant_expression : constant_expression
2943

2944
   BEGIN("path delay expression");
6✔
2945

2946
   (void)p_constant_expression();
3✔
2947
}
3✔
2948

2949
static void p_list_of_path_delay_expressions(void)
2✔
2950
{
2951
   // path_delay_expression { , path_delay_expression }
2952

2953
   BEGIN("list of path delay expressions");
4✔
2954

2955
   do {
3✔
2956
      p_path_delay_expression();
3✔
2957
   } while (optional(tCOMMA));
3✔
2958
}
2✔
2959

2960
static void p_path_delay_value(void)
2✔
2961
{
2962
   // list_of_path_delay_expressions | ( list_of_path_delay_expressions )
2963

2964
   BEGIN("path delay value");
4✔
2965

2966
   if (optional(tLPAREN)) {
2✔
2967
      p_list_of_path_delay_expressions();
1✔
2968
      consume(tRPAREN);
1✔
2969
   }
2970
   else
2971
      p_list_of_path_delay_expressions();
1✔
2972
}
2✔
2973

2974
static void p_specify_terminal_descriptor(void)
4✔
2975
{
2976
   // identifier [ [ constant_range_expression ] ]
2977

2978
   BEGIN("specify terminal descriptor");
8✔
2979

2980
   p_identifier();
4✔
2981
}
4✔
2982

2983
static void p_parallel_path_description(void)
2✔
2984
{
2985
   // ( specify_input_terminal_descriptor [ polarity_operator ] =>
2986
   //     specify_output_terminal_descriptor )
2987

2988
   BEGIN("parallel path description");
4✔
2989

2990
   consume(tLPAREN);
2✔
2991

2992
   p_specify_terminal_descriptor();
2✔
2993

2994
   consume(tASSOC);
2✔
2995

2996
   p_specify_terminal_descriptor();
2✔
2997

2998
   consume(tRPAREN);
2✔
2999
}
2✔
3000

3001
static void p_simple_path_declaration(void)
2✔
3002
{
3003
   // parallel_path_description = path_delay_value
3004
   //   | full_path_description = path_delay_value
3005

3006
   BEGIN("simple path declaration");
4✔
3007

3008
   p_parallel_path_description();
2✔
3009

3010
   consume(tEQ);
2✔
3011

3012
   p_path_delay_value();
2✔
3013
}
2✔
3014

3015
static void p_path_declaration(void)
2✔
3016
{
3017
   // simple_path_declaration ; | edge_sensitive_path_declaration ;
3018
   //   | state_dependent_path_declaration ;
3019

3020
   BEGIN("path declaration");
4✔
3021

3022
   p_simple_path_declaration();
2✔
3023

3024
   consume(tSEMI);
2✔
3025
}
2✔
3026

3027
static void p_specify_item(void)
2✔
3028
{
3029
   // specparam_declaration | pulsestyle_declaration | showcancelled_declaration
3030
   //   | path_declaration | system_timing_check
3031

3032
   BEGIN("specify item");
4✔
3033

3034
   switch (peek()) {
2✔
3035
   case tLPAREN:
2✔
3036
      p_path_declaration();
2✔
3037
      break;
2✔
3038
   default:
×
3039
      one_of(tLPAREN);
×
3040
   }
3041
}
2✔
3042

3043
static vlog_node_t p_specify_block(void)
1✔
3044
{
3045
   // specify { specify_item } endspecify
3046

3047
   BEGIN("specify block");
1✔
3048

3049
   consume(tSPECIFY);
1✔
3050

3051
   vlog_node_t v = vlog_new(V_SPECIFY);
1✔
3052

3053
   while (not_at_token(tENDSPECIFY))
3✔
3054
      p_specify_item();
2✔
3055

3056
   consume(tENDSPECIFY);
1✔
3057

3058
   vlog_set_loc(v, CURRENT_LOC);
1✔
3059
   return v;
1✔
3060
}
3061

3062
static vlog_node_t p_ordered_port_connection(void)
38✔
3063
{
3064
   // { attribute_instance } [ expression ]
3065

3066
   BEGIN("ordered port connection");
76✔
3067

3068
   return p_expression();
38✔
3069
}
3070

3071
static void p_list_of_port_connections(vlog_node_t inst)
17✔
3072
{
3073
   // ordered_port_connection { , ordered_port_connection }
3074
   //   | named_port_connection { , named_port_connection }
3075

3076
   BEGIN("list of port connections");
34✔
3077

3078
   do {
38✔
3079
      vlog_add_param(inst, p_ordered_port_connection());
38✔
3080
   } while (optional(tCOMMA));
38✔
3081
}
17✔
3082

3083
static vlog_node_t p_hierarchical_instance(ident_t module_id)
17✔
3084
{
3085
   // name_of_instance ( [ list_of_port_connections ] )
3086

3087
   BEGIN("hierarchical instance");
17✔
3088

3089
   vlog_node_t v = vlog_new(V_MOD_INST);
17✔
3090
   vlog_set_ident(v, p_identifier());
17✔
3091
   vlog_set_ident2(v, module_id);
17✔
3092

3093
   consume(tLPAREN);
17✔
3094

3095
   if (peek() != tRPAREN)
17✔
3096
      p_list_of_port_connections(v);
17✔
3097

3098
   consume(tRPAREN);
17✔
3099

3100
   vlog_set_loc(v, CURRENT_LOC);
17✔
3101
   return v;
17✔
3102
}
3103

3104
static void p_module_instantiation(vlog_node_t mod)
17✔
3105
{
3106
   // module_identifier [ parameter_value_assignment ] hierarchical_instance
3107
   //   { , hierarchical_instance } ;
3108

3109
   BEGIN("module instantiation");
34✔
3110

3111
   ident_t module_id = p_identifier();
17✔
3112

3113
   do {
17✔
3114
      vlog_add_stmt(mod, p_hierarchical_instance(module_id));
17✔
3115
   } while (optional(tCOMMA));
17✔
3116

3117
   consume(tSEMI);
17✔
3118
}
17✔
3119

3120
static void p_module_or_generate_item(vlog_node_t mod)
467✔
3121
{
3122
   // { attribute_instance } parameter_override
3123
   //   | { attribute_instance } gate_instantiation
3124
   //   | { attribute_instance } udp_instantiation
3125
   //   | { attribute_instance } module_instantiation
3126
   //   | { attribute_instance } module_common_item
3127

3128
   BEGIN("module or generate item");
934✔
3129

3130
   while (peek() == tATTRBEGIN)
473✔
3131
      p_attribute_instance();
6✔
3132

3133
   switch (peek()) {
467✔
3134
   case tALWAYS:
414✔
3135
   case tALWAYSCOMB:
3136
   case tALWAYSFF:
3137
   case tALWAYSLATCH:
3138
   case tWIRE:
3139
   case tSUPPLY0:
3140
   case tSUPPLY1:
3141
   case tREG:
3142
   case tSTRUCT:
3143
   case tUNION:
3144
   case tASSIGN:
3145
   case tINITIAL:
3146
   case tTYPEDEF:
3147
   case tENUM:
3148
   case tSVINT:
3149
   case tINTEGER:
3150
   case tSVREAL:
3151
   case tSHORTREAL:
3152
   case tREALTIME:
3153
   case tTASK:
3154
   case tFUNCTION:
3155
   case tLOCALPARAM:
3156
   case tPARAMETER:
3157
      p_module_common_item(mod);
414✔
3158
      break;
414✔
3159
   case tPULLDOWN:
36✔
3160
   case tPULLUP:
3161
   case tAND:
3162
   case tNAND:
3163
   case tOR:
3164
   case tNOR:
3165
   case tXOR:
3166
   case tXNOR:
3167
   case tNOT:
3168
   case tBUF:
3169
      p_gate_instantiation(mod);
36✔
3170
      break;
36✔
3171
   case tID:
17✔
3172
      p_module_instantiation(mod);
17✔
3173
      break;
17✔
3174
   default:
×
NEW
3175
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tSUPPLY0,
×
3176
             tSUPPLY1, tREG, tSTRUCT, tUNION, tASSIGN, tINITIAL, tTYPEDEF,
3177
             tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTASK,
3178
             tFUNCTION, tLOCALPARAM, tPARAMETER, tPULLDOWN, tPULLUP, tID,
3179
             tAND, tNAND, tOR, tNOR, tXOR, tXNOR, tNOT, tBUF);
UNCOV
3180
      drop_tokens_until(tSEMI);
×
3181
   }
3182
}
467✔
3183

3184
static void p_non_port_module_item(vlog_node_t mod)
470✔
3185
{
3186
   // generate_region | module_or_generate_item | specify_block
3187
   //   | { attribute_instance } specparam_declaration | program_declaration
3188
   //   | module_declaration | interface_declaration | timeunits_declaration
3189

3190
   BEGIN("non-port module item");
940✔
3191

3192
   switch (peek()) {
470✔
3193
   case tALWAYS:
467✔
3194
   case tALWAYSCOMB:
3195
   case tALWAYSFF:
3196
   case tALWAYSLATCH:
3197
   case tWIRE:
3198
   case tSUPPLY0:
3199
   case tSUPPLY1:
3200
   case tREG:
3201
   case tSTRUCT:
3202
   case tUNION:
3203
   case tASSIGN:
3204
   case tINITIAL:
3205
   case tPULLDOWN:
3206
   case tPULLUP:
3207
   case tID:
3208
   case tATTRBEGIN:
3209
   case tAND:
3210
   case tNAND:
3211
   case tOR:
3212
   case tNOR:
3213
   case tXOR:
3214
   case tXNOR:
3215
   case tNOT:
3216
   case tBUF:
3217
   case tTYPEDEF:
3218
   case tENUM:
3219
   case tSVINT:
3220
   case tINTEGER:
3221
   case tSVREAL:
3222
   case tSHORTREAL:
3223
   case tREALTIME:
3224
   case tTASK:
3225
   case tFUNCTION:
3226
   case tLOCALPARAM:
3227
   case tPARAMETER:
3228
      p_module_or_generate_item(mod);
467✔
3229
      break;
467✔
3230
   case tSPECIFY:
1✔
3231
      vlog_add_stmt(mod, p_specify_block());
1✔
3232
      break;
1✔
3233
   default:
2✔
3234
      one_of(tALWAYS, tALWAYSCOMB, tALWAYSFF, tALWAYSLATCH, tWIRE, tSUPPLY0,
2✔
3235
             tSUPPLY1, tREG, tSTRUCT, tUNION, tASSIGN, tPULLDOWN, tPULLUP,
3236
             tID, tATTRBEGIN, tAND, tNAND, tOR, tNOR, tXOR, tXNOR, tNOT,
3237
             tBUF, tTYPEDEF, tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL,
3238
             tREALTIME, tTASK, tFUNCTION, tLOCALPARAM, tPARAMETER, tSPECIFY);
3239
      drop_tokens_until(tSEMI);
2✔
3240
   }
3241
}
470✔
3242

3243
static void p_module_item(vlog_node_t mod)
527✔
3244
{
3245
   // port_declaration ; | non_port_module_item
3246

3247
   BEGIN("module item");
1,054✔
3248

3249
   if (scan(tINOUT, tINPUT, tOUTPUT)) {
527✔
3250
      p_port_declaration(mod);
57✔
3251
      consume(tSEMI);
57✔
3252
   }
3253
   else
3254
      p_non_port_module_item(mod);
470✔
3255
}
527✔
3256

3257
static void p_ansi_port_declaration(vlog_node_t mod, v_port_kind_t *kind,
53✔
3258
                                    bool *isreg)
3259
{
3260
   // [ net_port_header | interface_port_header ] port_identifier
3261
   //     { unpacked_dimension } [ = constant_expression ]
3262
   // | [ variable_port_header ] port_identifier { variable_dimension }
3263
   //     [ = constant_expression ]
3264
   // | [ port_direction ] . port_identifier ( [ expression ] )
3265

3266
   BEGIN("ANSI port declaration");
106✔
3267

3268
   vlog_node_t dt;
53✔
3269
   if (peek() != tID)
53✔
3270
      dt = p_net_port_header(kind, isreg);
36✔
3271
   else
3272
      dt = logic_type();
17✔
3273

3274
   ident_t id, ext;
53✔
3275
   p_external_identifier(&id, &ext);
53✔
3276

3277
   vlog_node_t v = vlog_new(V_PORT_DECL);
53✔
3278
   vlog_set_subkind(v, *kind);
53✔
3279
   vlog_set_ident(v, id);
53✔
3280
   vlog_set_ident2(v, ext);
53✔
3281
   vlog_set_type(v, dt);
53✔
3282
   vlog_set_loc(v, &state.last_loc);
53✔
3283

3284
   vlog_add_decl(mod, v);
53✔
3285

3286
   if (*isreg) {
53✔
3287
      vlog_node_t reg = vlog_new(V_VAR_DECL);
10✔
3288
      vlog_set_loc(reg, CURRENT_LOC);
10✔
3289
      vlog_set_ident(reg, id);
10✔
3290
      vlog_set_type(reg, dt);
10✔
3291

3292
      vlog_add_decl(mod, reg);
10✔
3293
   }
3294

3295
   vlog_node_t ref = vlog_new(V_REF);
53✔
3296
   vlog_set_loc(ref, CURRENT_LOC);
53✔
3297
   vlog_set_ident(ref, id);
53✔
3298
   vlog_set_ref(ref, v);
53✔
3299

3300
   vlog_add_port(mod, ref);
53✔
3301
}
53✔
3302

3303
static void p_list_of_port_declarations(vlog_node_t mod)
17✔
3304
{
3305
   // ( [ { attribute_instance } ansi_port_declaration
3306
   //   { , { attribute_instance } ansi_port_declaration } ] )
3307

3308
   BEGIN("list of port declarations");
34✔
3309

3310
   consume(tLPAREN);
17✔
3311

3312
   if (peek() != tRPAREN) {
17✔
3313
      v_port_kind_t kind = V_PORT_INPUT;
14✔
3314
      bool isreg = false;
14✔
3315
      do {
53✔
3316
         p_ansi_port_declaration(mod, &kind, &isreg);
53✔
3317
      } while (optional(tCOMMA));
53✔
3318
   }
3319

3320
   consume(tRPAREN);
17✔
3321
}
17✔
3322

3323
static void p_module_ansi_header(vlog_node_t mod)
91✔
3324
{
3325
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
3326
   //    { package_import_declaration } [ parameter_port_list ]
3327
   ///   [ list_of_port_declarations ] ;
3328

3329
   EXTEND("module ANSI header");
182✔
3330

3331
   if (peek() == tLPAREN)
91✔
3332
      p_list_of_port_declarations(mod);
17✔
3333

3334
   consume(tSEMI);
91✔
3335

3336
   vlog_set_loc(mod, CURRENT_LOC);
91✔
3337
}
91✔
3338

3339
static vlog_node_t p_port_reference(void)
64✔
3340
{
3341
   // port_identifier constant_select
3342

3343
   BEGIN("port reference");
128✔
3344

3345
   return p_constant_select(p_identifier());
64✔
3346
}
3347

3348
static vlog_node_t p_port_expression(void)
64✔
3349
{
3350
   // port_reference | { port_reference { , port_reference } }
3351

3352
   BEGIN("port expression");
128✔
3353

3354
   return p_port_reference();
64✔
3355
}
3356

3357
static vlog_node_t p_port(void)
64✔
3358
{
3359
   // [ port_expression ] | . port_identifier ( [ port_expression ] )
3360

3361
   BEGIN("port");
128✔
3362

3363
   return p_port_expression();
64✔
3364
}
3365

3366
static void p_list_of_ports(vlog_node_t mod)
21✔
3367
{
3368
   // ( port { , port } )
3369

3370
   BEGIN("list of ports");
42✔
3371

3372
   consume(tLPAREN);
21✔
3373

3374
   do {
64✔
3375
      p_port();
64✔
3376
   } while (optional(tCOMMA));
64✔
3377

3378
   consume(tRPAREN);
21✔
3379
}
21✔
3380

3381
static void p_module_nonansi_header(vlog_node_t mod)
21✔
3382
{
3383
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
3384
   //    { package_import_declaration } [ parameter_port_list ] list_of_ports ;
3385

3386
   EXTEND("module non-ANSI header");
42✔
3387

3388
   p_list_of_ports(mod);
21✔
3389

3390
   consume(tSEMI);
21✔
3391

3392
   vlog_set_loc(mod, CURRENT_LOC);
21✔
3393
}
21✔
3394

3395
static vlog_node_t p_module_declaration(void)
112✔
3396
{
3397
   // module_nonansi_header [ timeunits_declaration ] { module_item }
3398
   //      endmodule [ : module_identifier ]
3399
   //   | module_ansi_header [ timeunits_declaration ] { non_port_module_item }
3400
   //      endmodule [ : module_identifier ]
3401
   //   | { attribute_instance } module_keyword [ lifetime ] module_identifier
3402
   //      ( .* ) ; [ timeunits_declaration ] { module_item } endmodule
3403
   //      [ : module_identifier ]
3404
   //   | extern module_nonansi_header
3405
   //   | extern module_ansi_header
3406

3407
   BEGIN("module declaration");
112✔
3408

3409
   vlog_node_t mod = vlog_new(V_MODULE);
112✔
3410

3411
   while (peek() == tATTRBEGIN)
112✔
3412
      p_attribute_instance();
×
3413

3414
   consume(tMODULE);
112✔
3415

3416
   ident_t id, ext;
112✔
3417
   p_external_identifier(&id, &ext);
112✔
3418
   vlog_set_ident2(mod, id);
112✔
3419

3420
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
112✔
3421
   vlog_set_ident(mod, qual);
112✔
3422

3423
   if (peek() == tLPAREN && peek_nth(2) == tID)
112✔
3424
      p_module_nonansi_header(mod);
21✔
3425
   else
3426
      p_module_ansi_header(mod);
91✔
3427

3428
   while (not_at_token(tENDMODULE))
639✔
3429
      p_module_item(mod);
527✔
3430

3431
   consume(tENDMODULE);
112✔
3432

3433
   return mod;
112✔
3434
}
3435

3436
static void p_udp_port_list(vlog_node_t udp)
16✔
3437
{
3438
   // output_port_identifier , input_port_identifier { , input_port_identifier }
3439

3440
   BEGIN("UDP port list");
32✔
3441

3442
   vlog_node_t oref = vlog_new(V_REF);
16✔
3443
   vlog_set_ident(oref, p_identifier());
16✔
3444
   vlog_set_loc(oref, &state.last_loc);
16✔
3445

3446
   vlog_add_port(udp, oref);
16✔
3447

3448
   consume(tCOMMA);
16✔
3449

3450
   vlog_node_t iref = vlog_new(V_REF);
16✔
3451
   vlog_set_ident(iref, p_identifier());
16✔
3452
   vlog_set_loc(iref, &state.last_loc);
16✔
3453

3454
   vlog_add_port(udp, iref);
16✔
3455

3456
   while (optional(tCOMMA)) {
38✔
3457
      vlog_node_t iref = vlog_new(V_REF);
22✔
3458
      vlog_set_ident(iref, p_identifier());
22✔
3459
      vlog_set_loc(iref, &state.last_loc);
22✔
3460

3461
      vlog_add_port(udp, iref);
22✔
3462
   }
3463
}
16✔
3464

3465
static vlog_node_t p_udp_nonansi_declaration(void)
16✔
3466
{
3467
   // { attribute_instance } primitive udp_identifier ( udp_port_list ) ;
3468

3469
   BEGIN("UDP non-ANSI declaration");
16✔
3470

3471
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
16✔
3472

3473
   consume(tPRIMITIVE);
16✔
3474

3475
   ident_t id, ext;
16✔
3476
   p_external_identifier(&id, &ext);
16✔
3477
   vlog_set_ident2(udp, id);
16✔
3478

3479
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
16✔
3480
   vlog_set_ident(udp, qual);
16✔
3481

3482
   consume(tLPAREN);
16✔
3483

3484
   p_udp_port_list(udp);
16✔
3485

3486
   consume(tRPAREN);
16✔
3487
   consume(tSEMI);
16✔
3488

3489
   vlog_set_loc(udp, CURRENT_LOC);
16✔
3490
   return udp;
16✔
3491
}
3492

3493
static void p_list_of_udp_port_identifiers(vlog_node_t udp, v_port_kind_t kind)
17✔
3494
{
3495
   // port_identifier { , port_identifier }
3496

3497
   BEGIN("list of UDP port identifiers");
34✔
3498

3499
   do {
38✔
3500
      ident_t id, ext;
38✔
3501
      p_external_identifier(&id, &ext);
38✔
3502

3503
      vlog_node_t p = vlog_new(V_PORT_DECL);
38✔
3504
      vlog_set_subkind(p, kind);
38✔
3505
      vlog_set_ident(p, id);
38✔
3506
      vlog_set_ident2(p, ext);
38✔
3507
      vlog_set_type(p, logic_type());
38✔
3508
      vlog_set_loc(p, &state.last_loc);
38✔
3509

3510
      vlog_add_decl(udp, p);
38✔
3511
   } while (optional(tCOMMA));
38✔
3512
}
17✔
3513

3514
static void p_udp_output_declaration(vlog_node_t udp, bool *has_reg)
17✔
3515
{
3516
   // { attribute_instance } output port_identifier
3517
   //    | { attribute_instance } output reg port_identifier
3518
   //         [ = constant_expression ]
3519

3520
   BEGIN("UDP output declaration");
34✔
3521

3522
   consume(tOUTPUT);
17✔
3523

3524
   const bool isreg = optional(tREG);
17✔
3525

3526
   ident_t id, ext;
17✔
3527
   p_external_identifier(&id, &ext);
17✔
3528

3529
   vlog_node_t logic = logic_type();
17✔
3530

3531
   vlog_node_t v = vlog_new(V_PORT_DECL);
17✔
3532
   vlog_set_subkind(v, V_PORT_OUTPUT);
17✔
3533
   vlog_set_ident(v, id);
17✔
3534
   vlog_set_ident2(v, ext);
17✔
3535
   vlog_set_type(v, logic);
17✔
3536
   vlog_set_loc(v, &state.last_loc);
17✔
3537

3538
   vlog_add_decl(udp, v);
17✔
3539

3540
   if (isreg) {
17✔
3541
      vlog_node_t reg = vlog_new(V_VAR_DECL);
2✔
3542
      vlog_set_loc(reg, &state.last_loc);
2✔
3543
      vlog_set_ident(reg, id);
2✔
3544
      vlog_set_type(reg, logic);
2✔
3545

3546
      vlog_add_decl(udp, reg);
2✔
3547

3548
      *has_reg = true;
2✔
3549
   }
3550
}
17✔
3551

3552
static void p_udp_input_declaration(vlog_node_t udp)
17✔
3553
{
3554
   // { attribute_instance } input list_of_udp_port_identifiers
3555

3556
   BEGIN("UDP input declaration");
34✔
3557

3558
   consume(tINPUT);
17✔
3559

3560
   p_list_of_udp_port_identifiers(udp, V_PORT_INPUT);
17✔
3561
}
17✔
3562

3563
static vlog_node_t p_udp_reg_declaration(void)
7✔
3564
{
3565
   // { attribute_instance } reg variable_identifier
3566

3567
   BEGIN("UDP reg declaration");
7✔
3568

3569
   consume(tREG);
7✔
3570

3571
   ident_t id = p_identifier();
7✔
3572

3573
   vlog_node_t reg = vlog_new(V_VAR_DECL);
7✔
3574
   vlog_set_loc(reg, &state.last_loc);
7✔
3575
   vlog_set_ident(reg, id);
7✔
3576
   vlog_set_type(reg, logic_type());
7✔
3577

3578
   return reg;
7✔
3579
}
3580

3581
static void p_udp_port_declaration(vlog_node_t udp, bool *has_reg)
39✔
3582
{
3583
   // udp_output_declaration ; | udp_input_declaration ; | udp_reg_declaration ;
3584

3585
   BEGIN("UDP port declaration");
78✔
3586

3587
   switch (peek()) {
39✔
3588
   case tOUTPUT:
16✔
3589
      p_udp_output_declaration(udp, has_reg);
16✔
3590
      break;
16✔
3591
   case tINPUT:
16✔
3592
      p_udp_input_declaration(udp);
16✔
3593
      break;
16✔
3594
   case tREG:
7✔
3595
      vlog_add_decl(udp, p_udp_reg_declaration());
7✔
3596
      *has_reg = true;
7✔
3597
      break;
7✔
3598
   default:
×
3599
      one_of(tOUTPUT, tINPUT, tREG);
×
3600
      break;
×
3601
   }
3602

3603
   consume(tSEMI);
39✔
3604
}
39✔
3605

3606
static void p_udp_declaration_port_list(vlog_node_t udp, bool *has_reg)
1✔
3607
{
3608
   // udp_output_declaration , udp_input_declaration { , udp_input_declaration }
3609

3610
   BEGIN("UDP declaration port list");
2✔
3611

3612
   p_udp_output_declaration(udp, has_reg);
1✔
3613

3614
   consume(tCOMMA);
1✔
3615

3616
   do {
1✔
3617
      p_udp_input_declaration(udp);
1✔
3618
   } while (optional(tCOMMA));
1✔
3619

3620
   const int ndecls = vlog_decls(udp);
1✔
3621
   for (int i = 0; i < ndecls; i++) {
4✔
3622
      vlog_node_t p = vlog_decl(udp, i);
3✔
3623
      if (vlog_kind(p) != V_PORT_DECL)
3✔
3624
         continue;
1✔
3625

3626
      vlog_node_t ref = vlog_new(V_REF);
2✔
3627
      vlog_set_loc(ref, vlog_loc(p));
2✔
3628
      vlog_set_ident(ref, vlog_ident(p));
2✔
3629
      vlog_set_ref(ref, p);
2✔
3630

3631
      vlog_add_port(udp, ref);
2✔
3632
   }
3633
}
1✔
3634

3635
static char p_output_symbol(void)
79✔
3636
{
3637
   // 0 | 1 | x | X
3638

3639
   BEGIN("output symbol");
158✔
3640

3641
   if (consume(tUDPLEVEL)) {
79✔
3642
      switch (state.last_lval.i64) {
79✔
3643
      case '0':
79✔
3644
      case '1':
3645
      case 'x':
3646
      case 'X':
3647
         return (char)state.last_lval.i64;
79✔
3648
      default:
×
3649
         parse_error(&state.last_loc, "'%c' is not a valid output symbol",
×
3650
                  (char)state.last_lval.i64);
3651
         break;
3652
      }
3653
   }
3654

3655
   return 'x';
3656
}
3657

3658
static char p_level_symbol(void)
229✔
3659
{
3660
   // 0 | 1 | x | X | ? | b | B
3661

3662
   BEGIN("level symbol");
458✔
3663

3664
   if (consume(tUDPLEVEL))
229✔
3665
      return (char)state.last_lval.i64;
229✔
3666
   else
3667
      return 'x';
3668
}
3669

3670
static char p_next_state(void)
67✔
3671
{
3672
   // output_symbol | -
3673

3674
   BEGIN("next state");
134✔
3675

3676
   switch (peek()) {
67✔
3677
   case tMINUS:
21✔
3678
      consume(tMINUS);
21✔
3679
      return '-';
21✔
3680
   case tUDPLEVEL:
46✔
3681
      return p_output_symbol();
46✔
3682
   default:
×
3683
      one_of(tUDPLEVEL, tMINUS);
×
3684
      return '-';
×
3685
   }
3686
}
3687

3688
static char p_edge_symbol(void)
10✔
3689
{
3690
   // r | R | f | F | p | P | n | N | *
3691

3692
   BEGIN("edge symbol");
20✔
3693

3694
   if (consume(tUDPEDGE))
10✔
3695
      return (char)state.last_lval.i64;
10✔
3696
   else
3697
      return '*';
3698
}
3699

3700
static void p_level_input_list(text_buf_t *tb)
33✔
3701
{
3702
   // level_symbol { level_symbol }
3703

3704
   BEGIN("level input list");
66✔
3705

3706
   do {
96✔
3707
      tb_append(tb, p_level_symbol());
96✔
3708
   } while (not_at_token(tCOLON));
96✔
3709
}
33✔
3710

3711
static void p_edge_indicator(text_buf_t *tb)
67✔
3712
{
3713
   // ( level_symbol level_symbol ) | edge_symbol
3714

3715
   BEGIN("edge indicator");
134✔
3716

3717
   switch (peek()) {
67✔
3718
   case tUDPEDGE:
10✔
3719
      tb_append(tb, p_edge_symbol());
10✔
3720
      break;
10✔
3721
   case tUDPIND:
57✔
3722
      consume(tUDPIND);
57✔
3723
      tb_cat(tb, state.last_lval.str);
57✔
3724
      free(state.last_lval.str);
57✔
3725
      break;
57✔
3726
   default:
×
3727
      should_not_reach_here();
3728
   }
3729
}
67✔
3730

3731
static void p_seq_input_list(text_buf_t *tb)
67✔
3732
{
3733
   // level_input_list | edge_input_list
3734

3735
   BEGIN("sequential input list");
134✔
3736

3737
   bool have_edge = false;
67✔
3738
   do {
133✔
3739
      switch (peek()) {
133✔
3740
      case tUDPEDGE:
67✔
3741
      case tUDPIND:
3742
         p_edge_indicator(tb);
67✔
3743
         if (have_edge)
67✔
3744
            parse_error(&state.last_loc, "a sequential input list may have at "
1✔
3745
                        "most one edge indicator");
3746
         have_edge = true;
3747
         break;
3748

3749
      case tUDPLEVEL:
66✔
3750
         tb_append(tb, p_level_symbol());
66✔
3751
         break;
66✔
3752

3753
      default:
×
3754
         one_of(tUDPEDGE, tUDPIND, tUDPLEVEL);
×
3755
         break;
×
3756
      }
3757
   } while (not_at_token(tCOLON));
133✔
3758
}
67✔
3759

3760
static vlog_node_t p_combinational_entry(void)
33✔
3761
{
3762
   // level_input_list : output_symbol ;
3763

3764
   BEGIN("combinational entry");
66✔
3765

3766
   LOCAL_TEXT_BUF tb = tb_new();
33✔
3767
   p_level_input_list(tb);
33✔
3768

3769
   consume(tCOLON);
33✔
3770
   tb_append(tb, ':');
33✔
3771

3772
   tb_append(tb, p_output_symbol());
33✔
3773

3774
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
33✔
3775
   vlog_set_text(v, tb_get(tb));
33✔
3776

3777
   consume(tSEMI);
33✔
3778

3779
   vlog_set_loc(v, CURRENT_LOC);
33✔
3780
   return v;
33✔
3781
}
3782

3783
static vlog_node_t p_combinational_body(void)
8✔
3784
{
3785
   // table combinational_entry { combinational_entry } endtable
3786

3787
   BEGIN("combinational UDP body");
8✔
3788

3789
   consume(tTABLE);
8✔
3790

3791
   scan_as_udp();
8✔
3792

3793
   vlog_node_t v = vlog_new(V_UDP_TABLE);
8✔
3794
   vlog_set_subkind(v, V_UDP_COMB);
8✔
3795
   vlog_set_ident(v, ident_new("combinational"));
8✔
3796

3797
   do {
33✔
3798
      vlog_add_param(v, p_combinational_entry());
33✔
3799
   } while (not_at_token(tENDTABLE));
33✔
3800

3801
   scan_as_verilog();
8✔
3802

3803
   consume(tENDTABLE);
8✔
3804

3805
   vlog_set_loc(v, CURRENT_LOC);
8✔
3806
   return v;
8✔
3807
}
3808

3809
static vlog_node_t p_sequential_entry(void)
67✔
3810
{
3811
   // seq_input_list : current_state : next_state ;
3812

3813
   BEGIN("sequential entry");
134✔
3814

3815
   LOCAL_TEXT_BUF tb = tb_new();
67✔
3816
   p_seq_input_list(tb);
67✔
3817

3818
   consume(tCOLON);
67✔
3819
   tb_append(tb, ':');
67✔
3820

3821
   tb_append(tb, p_level_symbol());
67✔
3822

3823
   consume(tCOLON);
67✔
3824
   tb_append(tb, ':');
67✔
3825

3826
   tb_append(tb, p_next_state());
67✔
3827

3828
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
67✔
3829
   vlog_set_text(v, tb_get(tb));
67✔
3830

3831
   consume(tSEMI);
67✔
3832

3833
   vlog_set_loc(v, CURRENT_LOC);
67✔
3834
   return v;
67✔
3835
}
3836

3837
static vlog_node_t p_udp_initial_statement(void)
4✔
3838
{
3839
   // initial output_port_identifier = init_val ;
3840

3841
   BEGIN("UDP initial statement");
4✔
3842

3843
   consume(tINITIAL);
4✔
3844

3845
   vlog_node_t ref = vlog_new(V_REF);
4✔
3846
   vlog_set_ident(ref, p_identifier());
4✔
3847
   vlog_set_loc(ref, &state.last_loc);
4✔
3848

3849
   consume(tEQ);
4✔
3850

3851
   vlog_node_t v = vlog_new(V_BASSIGN);
4✔
3852
   vlog_set_target(v, ref);
4✔
3853
   vlog_set_value(v, p_integral_number());
4✔
3854

3855
   consume(tSEMI);
4✔
3856

3857
   vlog_set_loc(v, CURRENT_LOC);
4✔
3858
   return v;
4✔
3859
}
3860

3861
static vlog_node_t p_sequential_body(void)
9✔
3862
{
3863
   // [ udp_initial_statement ] table sequential_entry
3864
   //     { sequential_entry } endtable
3865

3866
   BEGIN("sequential UDP body");
9✔
3867

3868
   vlog_node_t v = vlog_new(V_UDP_TABLE);
9✔
3869
   vlog_set_subkind(v, V_UDP_SEQ);
9✔
3870
   vlog_set_ident(v, ident_new("sequential"));
9✔
3871

3872
   if (peek() == tINITIAL)
9✔
3873
      vlog_add_stmt(v, p_udp_initial_statement());
4✔
3874

3875
   consume(tTABLE);
9✔
3876

3877
   scan_as_udp();
9✔
3878

3879
   do {
67✔
3880
      vlog_add_param(v, p_sequential_entry());
67✔
3881
   } while (not_at_token(tENDTABLE));
67✔
3882

3883
   scan_as_verilog();
9✔
3884

3885
   consume(tENDTABLE);
9✔
3886

3887
   vlog_set_loc(v, CURRENT_LOC);
9✔
3888
   return v;
9✔
3889
}
3890

3891
static vlog_node_t p_udp_body(bool has_reg)
17✔
3892
{
3893
   // combinational_body | sequential_body
3894

3895
   BEGIN("UDP body");
34✔
3896

3897
   if (has_reg)
17✔
3898
      return p_sequential_body();
9✔
3899
   else
3900
      return p_combinational_body();
8✔
3901
}
3902

3903
static vlog_node_t p_udp_ansi_declaration(bool *has_reg)
1✔
3904
{
3905
   // { attribute_instance } primitive udp_identifier
3906
   //    ( udp_declaration_port_list ) ;
3907

3908
   BEGIN("UDP ANSI declaration");
1✔
3909

3910
   while (peek() == tATTRBEGIN)
1✔
3911
      p_attribute_instance();
×
3912

3913
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
1✔
3914

3915
   consume(tPRIMITIVE);
1✔
3916

3917
   ident_t id, ext;
1✔
3918
   p_external_identifier(&id, &ext);
1✔
3919
   vlog_set_ident2(udp, id);
1✔
3920

3921
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
1✔
3922
   vlog_set_ident(udp, qual);
1✔
3923

3924
   consume(tLPAREN);
1✔
3925

3926
   p_udp_declaration_port_list(udp, has_reg);
1✔
3927

3928
   consume(tRPAREN);
1✔
3929
   consume(tSEMI);
1✔
3930

3931
   vlog_set_loc(udp, CURRENT_LOC);
1✔
3932
   return udp;
1✔
3933
}
3934

3935
static vlog_node_t p_udp_declaration(void)
17✔
3936
{
3937
   // udp_nonansi_declaration udp_port_declaration { udp_port_declaration }
3938
   //        udp_body endprimitive [ : udp_identifier ]
3939
   //   | udp_ansi_declaration udp_body endprimitive [ : udp_identifier ]
3940
   //   | extern udp_nonansi_declaration
3941
   //   | extern udp_ansi_declaration
3942
   //   | { attribute_instance } primitive udp_identifier ( .* ) ;
3943
   //        { udp_port_declaration } udp_body endprimitive [ : udp_identifier ]
3944

3945
   BEGIN("UDP declaration");
17✔
3946

3947
   bool has_reg = false;
17✔
3948
   vlog_node_t udp;
17✔
3949
   if (peek_nth(4) == tID) {
17✔
3950
      udp = p_udp_nonansi_declaration();
16✔
3951

3952
      do {
39✔
3953
         p_udp_port_declaration(udp, &has_reg);
39✔
3954
      } while (not_at_token(tTABLE, tINITIAL));
39✔
3955
   }
3956
   else
3957
      udp = p_udp_ansi_declaration(&has_reg);
1✔
3958

3959
   vlog_add_stmt(udp, p_udp_body(has_reg));
17✔
3960

3961
   consume(tENDPRIMITIVE);
17✔
3962

3963
   return udp;
17✔
3964
}
3965

3966
static vlog_node_t p_description(void)
129✔
3967
{
3968
   // module_declaration | udp_declaration | interface_declaration
3969
   //   | program_declaration | package_declaration
3970
   //   | { attribute_instance } package_item
3971
   //   | { attribute_instance } bind_directive
3972
   //   | config_declaration
3973

3974
   BEGIN("description");
258✔
3975

3976
   switch (peek()) {
129✔
3977
   case tMODULE:
112✔
3978
      return p_module_declaration();
112✔
3979
   case tPRIMITIVE:
17✔
3980
      return p_udp_declaration();
17✔
3981
   default:
×
3982
      expect(tPRIMITIVE, tMODULE);
×
3983
      return NULL;
×
3984
   }
3985
}
3986

3987
static void p_timescale_compiler_directive(void)
9✔
3988
{
3989
   // `timescale time_unit / time_precision
3990

3991
   BEGIN("timescale compiler directive");
18✔
3992

3993
   consume(tTIMESCALE);
9✔
3994

3995
   consume(tUNSIGNED);
9✔
3996
   char *unit_value LOCAL = state.last_lval.str;
18✔
3997

3998
   consume(tID);
9✔
3999
   char *unit_name LOCAL = state.last_lval.str;
18✔
4000

4001
   consume(tOVER);
9✔
4002

4003
   consume(tUNSIGNED);
9✔
4004
   char *prec_value LOCAL = state.last_lval.str;
18✔
4005

4006
   consume(tID);
9✔
4007
   char *prec_name LOCAL = state.last_lval.str;
18✔
4008

4009
   set_timescale(unit_value, unit_name, prec_value, prec_name, CURRENT_LOC);
9✔
4010
}
9✔
4011

4012
static void p_defaultnettype_compiler_directive(void)
12✔
4013
{
4014
   // `default_nettype wire | tri | tri0 | tri1 | wand | triand | wor | trior | trireg | uwire | none
4015

4016
   BEGIN("default_nettype directive");
24✔
4017

4018
   consume(tDEFNETTYPE);
12✔
4019

4020
   one_of(tWIRE, tTRI, tTRI0, tTRI1, tWAND, tTRIAND, tWOR, tTRIOR, tTRIREG, tUWIRE, tNONE);
12✔
4021

4022
   // TODO: do something with the directive
4023
}
12✔
4024

4025
static void p_keywords_directive(void)
1✔
4026
{
4027
   // `begin_keywords "version_specifier"
4028

4029
   BEGIN("keywords directive");
1✔
4030

4031
   consume(tBEGINKEYWORDS);
1✔
4032

4033
   consume(tSTRING);
1✔
4034
   free(state.last_lval.str);
1✔
4035
}
1✔
4036

4037
static void p_endkeywords_directive(void)
1✔
4038
{
4039
   // `end_keywords
4040

4041
   BEGIN("endkeywords directive");
2✔
4042

4043
   consume(tENDKEYWORDS);
1✔
4044
}
1✔
4045

4046
static void p_directive_list(void)
130✔
4047
{
4048
   BEGIN("directive list");
130✔
4049

4050
   for (;;) {
153✔
4051
      switch (peek()) {
153✔
4052
      case tDEFNETTYPE:
12✔
4053
         p_defaultnettype_compiler_directive();
12✔
4054
         break;
12✔
4055
      case tTIMESCALE:
9✔
4056
         p_timescale_compiler_directive();
9✔
4057
         break;
9✔
4058
      case tBEGINKEYWORDS:
1✔
4059
         p_keywords_directive();
1✔
4060
         break;
1✔
4061
      case tENDKEYWORDS:
1✔
4062
         p_endkeywords_directive();
1✔
4063
         break;
1✔
4064
      default:
4065
         return;
130✔
4066
      }
4067
   }
4068
}
4069

4070
vlog_node_t vlog_parse(void)
226✔
4071
{
4072
   state.n_correct = RECOVER_THRESH;
226✔
4073

4074
   scan_as_verilog();
226✔
4075

4076
   if (peek() == tEOF)
226✔
4077
      return NULL;
4078

4079
   p_directive_list();
130✔
4080

4081
   make_new_arena();
130✔
4082

4083
   if (peek() == tEOF)
130✔
4084
      return NULL;
4085

4086
   return p_description();
129✔
4087
}
4088

4089
void reset_verilog_parser(void)
186✔
4090
{
4091
   state.tokenq_head = state.tokenq_tail = 0;
186✔
4092
}
186✔
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