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

nickg / nvc / 13798777898

11 Mar 2025 08:20PM UTC coverage: 92.333% (+0.02%) from 92.318%
13798777898

push

github

nickg
Implement __FILE__ and __LINE__ in Verilog preprocessor

3 of 3 new or added lines in 1 file covered. (100.0%)

68 existing lines in 2 files now uncovered.

68139 of 73797 relevant lines covered (92.33%)

432233.27 hits per line

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

95.11
/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

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

113
   state.hint_str = r->old_hint;
21,921✔
114

115
   if (r->old_start_loc.first_line != LINE_INVALID)
21,921✔
116
      state.start_loc = r->old_start_loc;
8,286✔
117
}
21,921✔
118

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

126
static token_t peek_nth(int n)
35,053✔
127
{
128
   while (((state.tokenq_head - state.tokenq_tail) & (TOKENQ_SIZE - 1)) < n) {
44,848✔
129
      const token_t token = processed_yylex();
9,795✔
130

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

134
      extern yylval_t yylval;
9,795✔
135

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

140
      state.tokenq_head = next;
9,795✔
141
   }
142

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

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

151
   if (state.start_loc.first_line == LINE_INVALID)
9,699✔
152
      state.start_loc = state.tokenq[state.tokenq_tail].loc;
5,237✔
153

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

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

159
   state.nopt_hist = 0;
9,699✔
160
}
9,699✔
161

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

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

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

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

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

196
         if (first && (tok != -1))
25✔
197
            diag_printf(d, "one of ");
2✔
198
         else if (!first)
23✔
199
            diag_printf(d, (tok == -1) ? " or " : ", ");
42✔
200

201
         diag_printf(d, "$yellow$%s$$", token_str(tmp));
25✔
202

203
         first = false;
25✔
204
      }
205

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

211
   state.n_correct = 0;
8✔
212

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

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

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

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

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

256
   token_t p = peek();
2,843✔
257
   bool found = false;
2,843✔
258

259
   while (!found) {
2,843✔
260
      const int tok = va_arg(ap, token_t);
7,634✔
261
      if (tok == -1)
7,634✔
262
         break;
263
      else if (p == tok)
5,437✔
264
         found = true;
265
   }
266

267
   va_end(ap);
2,843✔
268
   return found;
2,843✔
269
}
270

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

276
   token_t p = peek();
550✔
277
   bool found = false;
550✔
278

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

287
   va_end(ap);
550✔
288

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

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

302
static const loc_t *_diff_loc(const loc_t *start, const loc_t *end)
5,908✔
303
{
304
   static loc_t result;
5,908✔
305

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

428
   (void)p_identifier();
6✔
429

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

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

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

440
   consume(tATTRBEGIN);
6✔
441

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

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

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

453
   BEGIN("unsigned number");
666✔
454

455
   consume(tUNSIGNED);
666✔
456

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

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

468
   BEGIN("integral number");
1,078✔
469

470
   if (peek() == tUNSIGNED)
539✔
471
      return p_unsigned_number();
483✔
472
   else {
473
      consume(tNUMBER);
56✔
474

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

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

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

490
   consume(tREAL);
6✔
491

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

498
static vlog_node_t p_number(void)
541✔
499
{
500
   // integral_number | real_number
501

502
   BEGIN("number");
1,082✔
503

504
   if (peek() == tREAL)
541✔
505
      return p_real_number();
6✔
506
   else
507
      return p_integral_number();
535✔
508
}
509

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

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

516
   consume(tSTRING);
298✔
517

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

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

525
   return v;
298✔
526
}
527

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

532
   BEGIN("primary literal");
1,678✔
533

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

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

551
   EXTEND("constant bit select");
366✔
552

553
   if (peek() == tLSQUARE) {
183✔
554
      vlog_node_t v = vlog_new(V_BIT_SELECT);
3✔
555
      vlog_set_ident(v, id);
3✔
556

557
      while (optional(tLSQUARE)) {
6✔
558
         vlog_add_param(v, p_constant_expression());
3✔
559
         consume(tRSQUARE);
3✔
560
      }
561

562
      vlog_set_loc(v, CURRENT_LOC);
3✔
563
      return v;
3✔
564
   }
565
   else {
566
      vlog_node_t v = vlog_new(V_REF);
180✔
567
      vlog_set_ident(v, id);
180✔
568
      vlog_set_loc(v, CURRENT_LOC);
180✔
569
      return v;
180✔
570
   }
571
}
572

573
static vlog_node_t p_constant_select(ident_t id)
183✔
574
{
575
   // [ { . member_identifier constant_bit_select } . member_identifier ]
576
   //    constant_bit_select [ [ constant_part_select_range ] ]
577

578
   EXTEND("constant select");
366✔
579

580
   return p_constant_bit_select(id);
183✔
581
}
582

583
static vlog_node_t p_constant_primary(void)
98✔
584
{
585
   // primary_literal | ps_parameter_identifier constant_select
586
   //   | specparam_identifier [ [ constant_range_expression ] ]
587
   //   | genvar_identifier | formal_port_identifier constant_select
588
   //   | [ package_scope | class_scope ] enum_identifier
589
   //   | constant_concatenation [ [ constant_range_expression ] ]
590
   //   | constant_multiple_concatenation [ [ constant_range_expression ] ]
591
   //   | constant_function_call | constant_let_expression
592
   //   | ( constant_mintypmax_expression )
593
   //   | constant_cast | constant_assignment_pattern_expression
594
   //   | type_reference
595

596
   BEGIN("constant primary");
196✔
597

598
   switch (peek()) {
98✔
599
   case tNUMBER:
97✔
600
   case tUNSIGNED:
601
   case tSTRING:
602
   case tREAL:
603
      return p_primary_literal();
97✔
604
   case tID:
1✔
605
      return p_constant_select(p_identifier());
1✔
606
   default:
×
607
      one_of(tNUMBER, tUNSIGNED, tSTRING, tREAL, tID);
×
608
      return dummy_expression();
×
609
   }
610
}
611

612
static vlog_node_t p_constant_expression(void)
98✔
613
{
614
   // constant_primary | unary_operator { attribute_instance } constant_primary
615
   //   | constant_expression binary_operator { attribute_instance }
616
   //       constant_expression
617
   //   | constant_expression ? { attribute_instance }
618
   //       constant_expression : constant_expression
619

620
   BEGIN("constant expression");
196✔
621

622
   return p_constant_primary();
98✔
623
}
624

625
static void p_constant_range(vlog_node_t *left, vlog_node_t *right)
46✔
626
{
627
   // constant_expression : constant_expression
628

629
   BEGIN("constant range");
46✔
630

631
   *left = p_constant_expression();
46✔
632

633
   consume(tCOLON);
46✔
634

635
   *right = p_constant_expression();
46✔
636
}
46✔
637

638
static vlog_node_t p_packed_dimension(void)
46✔
639
{
640
   // [ constant_range ] | unsized_dimension
641

642
   BEGIN("packed dimension");
46✔
643

644
   consume(tLSQUARE);
46✔
645

646
   vlog_node_t left, right;
46✔
647
   p_constant_range(&left, &right);
46✔
648

649
   consume(tRSQUARE);
46✔
650

651
   vlog_node_t v = vlog_new(V_DIMENSION);
46✔
652
   vlog_set_subkind(v, V_DIM_PACKED);
46✔
653
   vlog_set_left(v, left);
46✔
654
   vlog_set_right(v, right);
46✔
655
   vlog_set_loc(v, CURRENT_LOC);
46✔
656

657
   return v;
46✔
658
}
659

660
static vlog_node_t p_data_type_or_void(void)
9✔
661
{
662
   // data_type | void
663

664
   BEGIN("data type or void");
18✔
665

666
   if (optional(tVOID))
9✔
667
      return NULL;
668
   else
669
      return p_data_type();
9✔
670
}
671

672
static void p_struct_union_member(vlog_node_t v)
9✔
673
{
674
   // { attribute_instance } [ random_qualifier ] data_type_or_void
675
   //    list_of_variable_decl_assignments ;
676

677
   BEGIN("struct or union member");
18✔
678

679
   while (peek() == tATTRBEGIN)
9✔
680
      p_attribute_instance();
×
681

682
   vlog_node_t dt = p_data_type_or_void();
9✔
683
   p_list_of_variable_decl_assignments(v, dt);
9✔
684

685
   consume(tSEMI);
9✔
686
}
9✔
687

688
static void p_enum_name_declaration(vlog_node_t parent)
4✔
689
{
690
   // enum_identifier [ [ integral_number [ : integral_number ] ] ]
691
   //   [ = constant_expression ]
692

693
   BEGIN("enum name declaration");
8✔
694

695
   vlog_node_t v = vlog_new(V_ENUM_NAME);
4✔
696
   vlog_set_ident(v, p_identifier());
4✔
697
   vlog_set_type(v, parent);
4✔
698

699
   vlog_add_decl(parent, v);
4✔
700
}
4✔
701

702
static vlog_node_t p_integer_atom_type(void)
13✔
703
{
704
   // byte | shortint | int | longint | integer | time
705

706
   BEGIN("integer atom type");
13✔
707

708
   data_type_t dt = DT_BYTE;
13✔
709
   switch (one_of(tBYTE, tSHORTINT, tSVINT, tLONGINT, tINTEGER, tTIME)) {
13✔
710
   case tBYTE:     dt = DT_BYTE; break;
711
   case tSHORTINT: dt = DT_SHORTINT; break;
712
   case tSVINT:    dt = DT_INT; break;
713
   case tLONGINT:  dt = DT_LONGINT; break;
714
   case tINTEGER:  dt = DT_INTEGER; break;
715
   case tTIME:     dt = DT_TIME; break;
716
   }
717

718
   vlog_node_t v = vlog_new(V_DATA_TYPE);
13✔
719
   vlog_set_subkind(v, dt);
13✔
720
   vlog_set_loc(v, &state.last_loc);
13✔
721
   return v;
13✔
722
}
723

724
static vlog_node_t p_integer_vector_type(void)
121✔
725
{
726
   //  bit | logic | reg
727

728
   BEGIN("integer vector type");
121✔
729

730
   data_type_t dt = DT_LOGIC;
121✔
731
   switch (one_of(tBIT, tLOGIC, tREG)) {
121✔
732
   case tBIT:    dt = DT_BIT; break;
×
733
   case tLOGIC:
734
   case tREG:    dt = DT_LOGIC; break;
735
   }
736

737
   vlog_node_t v = vlog_new(V_DATA_TYPE);
121✔
738
   vlog_set_subkind(v, dt);
121✔
739
   vlog_set_loc(v, &state.last_loc);
121✔
740
   return v;
121✔
741
}
742

743
static vlog_node_t p_non_integer_type(void)
5✔
744
{
745
   // shortreal | real | realtime
746

747
   BEGIN("non-integer type");
5✔
748

749
   data_type_t dt = DT_REAL;
5✔
750
   switch (one_of(tSVREAL, tSHORTREAL, tREALTIME)) {
5✔
751
   case tSVREAL:    dt = DT_REAL; break;
752
   case tSHORTREAL: dt = DT_SHORTREAL; break;
1✔
753
   case tREALTIME:  dt = DT_REALTIME; break;
1✔
754
   }
755

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

762
static vlog_node_t p_struct_union(void)
5✔
763
{
764
   // struct | union [ tagged ]
765

766
   BEGIN("struct or union");
10✔
767

768
   switch (one_of(tSTRUCT, tUNION)) {
5✔
769
   case tUNION:
2✔
770
      {
771
         vlog_node_t v = vlog_new(V_UNION_DECL);
2✔
772
         optional(tTAGGED);
2✔
773
         return v;
2✔
774
      }
775
   case tSTRUCT:
3✔
776
   default:
777
      return vlog_new(V_STRUCT_DECL);
3✔
778
   }
779
}
780

781
static vlog_node_t p_data_type(void)
146✔
782
{
783
   // integer_vector_type [ signing ] { packed_dimension }
784
   //   | integer_atom_type [ signing ] | non_integer_type
785
   //   | struct_union [ packed [ signing ] ]
786
   //       { struct_union_member { struct_union_member } } { packed_dimension }
787
   //   | enum [ enum_base_type ] { enum_name_declaration
788
   //       { , enum_name_declaration } } { packed_dimension }
789
   //   | string | chandle
790
   //   | virtual [ interface ] interface_identifier
791
   //       [ parameter_value_assignment ] [ . modport_identifier ]
792
   //   | [ class_scope | package_scope ] type_identifier { packed_dimension }
793
   //   | class_type | event | ps_covergroup_identifier | type_reference
794

795
   BEGIN("data type");
292✔
796

797
   switch (peek()) {
146✔
798
   case tBIT:
121✔
799
   case tLOGIC:
800
   case tREG:
801
      {
802
         vlog_node_t v = p_integer_vector_type();
121✔
803

804
         while (peek() == tLSQUARE)
145✔
805
            vlog_add_range(v, p_packed_dimension());
24✔
806

807
         return v;
808
      }
809

810
   case tBYTE:
13✔
811
   case tSHORTINT:
812
   case tSVINT:
813
   case tLONGINT:
814
   case tINTEGER:
815
   case tTIME:
816
      return p_integer_atom_type();
13✔
817

818
   case tSVREAL:
5✔
819
   case tREALTIME:
820
   case tSHORTREAL:
821
      return p_non_integer_type();
5✔
822

823
   case tSTRUCT:
5✔
824
   case tUNION:
825
      {
826
         vlog_node_t v = p_struct_union();
5✔
827

828
         (void)optional(tPACKED);
5✔
829

830
         consume(tLBRACE);
5✔
831

832
         do {
9✔
833
            p_struct_union_member(v);
9✔
834
         } while (not_at_token(tRBRACE));
9✔
835

836
         consume(tRBRACE);
5✔
837

838
         if (peek() == tLSQUARE)
5✔
839
            vlog_add_range(v, p_packed_dimension());
×
840

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

845
   case tENUM:
2✔
846
      {
847
         consume(tENUM);
2✔
848

849
         vlog_node_t v = vlog_new(V_ENUM_DECL);
2✔
850

851
         consume(tLBRACE);
2✔
852

853
         do {
4✔
854
            p_enum_name_declaration(v);
4✔
855
         } while (optional(tCOMMA));
4✔
856

857
         consume(tRBRACE);
2✔
858

859
         while (peek() == tLSQUARE)
3✔
860
            vlog_add_range(v, p_packed_dimension());
1✔
861

862
         vlog_set_loc(v, CURRENT_LOC);
2✔
863
         return v;
2✔
864
      }
865

866
   default:
×
867
      one_of(tBIT, tLOGIC, tREG, tBYTE, tSHORTINT, tSVINT, tLONGINT, tINTEGER,
×
868
             tTIME, tSVREAL, tREALTIME, tSHORTREAL, tSTRUCT, tUNION, tENUM);
869
      return logic_type();
×
870
   }
871
}
872

873
static vlog_node_t p_implicit_data_type(void)
158✔
874
{
875
   // [ signing ] { packed_dimension }
876

877
   BEGIN("implicit data type");
158✔
878

879
   vlog_node_t v = vlog_new(V_DATA_TYPE);
158✔
880
   vlog_set_subkind(v, DT_LOGIC);
158✔
881

882
   while (peek() == tLSQUARE)
179✔
883
      vlog_add_range(v, p_packed_dimension());
21✔
884

885
   vlog_set_loc(v, CURRENT_LOC);
158✔
886
   return v;
158✔
887
}
888

889
static vlog_node_t p_data_type_or_implicit(void)
286✔
890
{
891
   // data_type | implicit_data_type
892

893
   BEGIN("data type or implicit");
572✔
894

895
   if (scan(tREG, tSTRUCT, tUNION, tENUM, tSVINT, tINTEGER, tSVREAL,
286✔
896
            tSHORTREAL, tREALTIME, tLOGIC))
897
      return p_data_type();
129✔
898
   else
899
      return p_implicit_data_type();
157✔
900
}
901

902
static vlog_node_t p_net_port_type(void)
90✔
903
{
904
   // [ net_type ] data_type_or_implicit | net_type_identifier
905
   //   | interconnect implicit_data_type
906

907
   BEGIN("net port type");
180✔
908

909
   return p_data_type_or_implicit();
90✔
910
}
911

912
static vlog_node_t p_var_data_type(void)
3✔
913
{
914
   // data_type | var data_type_or_implicit
915

916
   BEGIN("var data type");
6✔
917

918
   return p_data_type();
3✔
919
}
920

921
static vlog_node_t p_variable_port_type(void)
3✔
922
{
923
   // var_data_type
924

925
   BEGIN("variable port type");
6✔
926

927
   return p_var_data_type();
3✔
928
}
929

930
static void p_list_of_port_identifiers(vlog_node_t mod, v_port_kind_t kind,
57✔
931
                                       bool isreg, vlog_node_t datatype)
932
{
933
   // port_identifier { unpacked_dimension }
934
   //    { , port_identifier { unpacked_dimension } }
935

936
   BEGIN("list of port identifiers");
114✔
937

938
   do {
65✔
939
      ident_t id, ext;
65✔
940
      p_external_identifier(&id, &ext);
65✔
941

942
      vlog_node_t v = vlog_new(V_PORT_DECL);
65✔
943
      vlog_set_subkind(v, kind);
65✔
944
      vlog_set_ident(v, id);
65✔
945
      vlog_set_ident2(v, ext);
65✔
946
      vlog_set_type(v, datatype);
65✔
947
      vlog_set_loc(v, &state.last_loc);
65✔
948

949
      vlog_add_decl(mod, v);
65✔
950

951
      if (isreg) {
65✔
952
         vlog_node_t reg = vlog_new(V_VAR_DECL);
3✔
953
         vlog_set_loc(reg, vlog_loc(v));
3✔
954
         vlog_set_ident(reg, id);
3✔
955
         vlog_set_type(reg, datatype);
3✔
956

957
         vlog_add_decl(mod, reg);
3✔
958
      }
959

960
      vlog_node_t ref = vlog_new(V_REF);
65✔
961
      vlog_set_loc(ref, CURRENT_LOC);
65✔
962
      vlog_set_ident(ref, id);
65✔
963
      vlog_set_ref(ref, v);
65✔
964

965
      vlog_add_port(mod, ref);
65✔
966
   } while (optional(tCOMMA));
65✔
967
}
57✔
968

969
static void p_inout_declaration(vlog_node_t mod)
1✔
970
{
971
   // inout net_port_type list_of_port_identifiers
972

973
   BEGIN("inout declaration");
2✔
974

975
   consume(tINOUT);
1✔
976

977
   vlog_node_t dt = p_net_port_type();
1✔
978
   p_list_of_port_identifiers(mod, V_PORT_INOUT, false, dt);
1✔
979
}
1✔
980

981
static void p_input_declaration(vlog_node_t mod)
33✔
982
{
983
   // input net_port_type list_of_port_identifiers
984
   //   | input variable_port_type list_of_variable_identifiers
985

986
   BEGIN("input declaration");
66✔
987

988
   consume(tINPUT);
33✔
989

990
   bool isreg = false;
33✔
991
   vlog_node_t dt;
33✔
992
   switch (peek()) {
33✔
993
   case tREG:
×
994
      dt = p_variable_port_type();
×
995
      isreg = true;
×
996
      break;
×
997
   default:
33✔
998
      dt = p_net_port_type();
33✔
999
      break;
33✔
1000
   }
1001

1002
   p_list_of_port_identifiers(mod, V_PORT_INPUT, isreg, dt);
33✔
1003
}
33✔
1004

1005
static void p_output_declaration(vlog_node_t mod)
23✔
1006
{
1007
   // output net_port_type list_of_port_identifiers
1008
   //   | output variable_port_type list_of_variable_port_identifiers
1009

1010
   BEGIN("output declaration");
46✔
1011

1012
   consume(tOUTPUT);
23✔
1013

1014
   bool isreg = false;
23✔
1015
   vlog_node_t dt;
23✔
1016
   switch (peek()) {
23✔
1017
   case tREG:
3✔
1018
      dt = p_variable_port_type();
3✔
1019
      isreg = true;
3✔
1020
      break;
3✔
1021
   default:
20✔
1022
      dt = p_net_port_type();
20✔
1023
      break;
20✔
1024
   }
1025

1026
   p_list_of_port_identifiers(mod, V_PORT_OUTPUT, isreg, dt);
23✔
1027
}
23✔
1028

1029
static void p_port_declaration(vlog_node_t mod)
57✔
1030
{
1031
   // { attribute_instance } inout_declaration
1032
   //   | { attribute_instance } input_declaration
1033
   //   | { attribute_instance } output_declaration
1034
   //   | { attribute_instance } ref_declaration
1035
   //   | { attribute_instance } interface_port_declaration
1036

1037
   BEGIN("port declaration");
114✔
1038

1039
   switch (peek()) {
57✔
1040
   case tINOUT: p_inout_declaration(mod); break;
1✔
1041
   case tINPUT: p_input_declaration(mod); break;
33✔
1042
   case tOUTPUT: p_output_declaration(mod); break;
23✔
1043
   default: should_not_reach_here();
1044
   }
1045
}
57✔
1046

1047
static vlog_node_t p_net_port_header(v_port_kind_t *kind, bool *isreg)
36✔
1048
{
1049
   // [ port_direction ] net_port_type
1050

1051
   BEGIN("net port header");
72✔
1052

1053
   if (optional(tINPUT)) {
36✔
1054
      *kind = V_PORT_INPUT;
21✔
1055
      *isreg = (peek() == tREG);
21✔
1056
   }
1057
   else if (optional(tINOUT)) {
15✔
1058
      *kind = V_PORT_INOUT;
×
1059
      *isreg = false;
×
1060
   }
1061
   else if (optional(tOUTPUT)) {
15✔
1062
      *kind = V_PORT_OUTPUT;
15✔
1063
      *isreg = (peek() == tREG);
15✔
1064
   }
1065

1066
   return p_net_port_type();
36✔
1067
}
1068

1069
static vlog_node_t p_bit_select(ident_t id)
924✔
1070
{
1071
   // { [ expression ] }
1072

1073
   EXTEND("bit select");
1,848✔
1074

1075
   if (peek() == tLSQUARE) {
924✔
1076
      vlog_node_t v = vlog_new(V_BIT_SELECT);
9✔
1077
      vlog_set_ident(v, id);
9✔
1078

1079
      while (optional(tLSQUARE)) {
18✔
1080
         vlog_add_param(v, p_expression());
9✔
1081
         consume(tRSQUARE);
9✔
1082
      }
1083

1084
      vlog_set_loc(v, CURRENT_LOC);
9✔
1085
      return v;
9✔
1086
   }
1087
   else {
1088
      vlog_node_t v = vlog_new(V_REF);
915✔
1089
      vlog_set_ident(v, id);
915✔
1090
      vlog_set_loc(v, CURRENT_LOC);
915✔
1091
      return v;
915✔
1092
   }
1093
}
1094

1095

1096
static vlog_node_t p_select(ident_t id)
924✔
1097
{
1098
   // [ { . member_identifier bit_select } . member_identifier ]
1099
   //    bit_select [ [ part_select_range ] ]
1100

1101
   EXTEND("select");
1,848✔
1102

1103
   return p_bit_select(id);
924✔
1104
}
1105

1106
static void p_list_of_arguments(vlog_node_t call)
298✔
1107
{
1108
   // [ expression ] { , [ expression ] } { , . identifier ( [ expression ] ) }
1109
   //    | . identifier ( [ expression ] ) { , . identifier ( [ expression ] ) }
1110

1111
   BEGIN("list of arguments");
596✔
1112

1113
   do {
575✔
1114
      if (peek() == tCOMMA) {
575✔
1115
         vlog_node_t v = vlog_new(V_EMPTY);
9✔
1116
         vlog_set_loc(v, &state.last_loc);
9✔
1117
         vlog_add_param(call, v);
9✔
1118
      }
1119
      else
1120
         vlog_add_param(call, p_expression());
566✔
1121
   } while (optional(tCOMMA));
575✔
1122
}
298✔
1123

1124
static vlog_node_t p_system_tf_call(vlog_kind_t kind)
430✔
1125
{
1126
   // system_tf_identifier [ ( list_of_arguments ) ]
1127

1128
   BEGIN("system task or function call");
430✔
1129

1130
   vlog_node_t v = vlog_new(kind);
430✔
1131
   vlog_set_ident(v, p_system_tf_identifier());
430✔
1132

1133
   if (optional(tLPAREN)) {
430✔
1134
      p_list_of_arguments(v);
298✔
1135
      consume(tRPAREN);
298✔
1136
   }
1137

1138
   vlog_set_loc(v, CURRENT_LOC);
430✔
1139
   return v;
430✔
1140
}
1141

1142
static vlog_node_t p_subroutine_call(vlog_kind_t kind)
430✔
1143
{
1144
   // tf_call | system_tf_call | method_call | [ std:: ] randomize_call
1145

1146
   BEGIN("subroutine call");
860✔
1147

1148
   return p_system_tf_call(kind);
430✔
1149
}
1150

1151
static vlog_node_t p_mintypmax_expression(void)
4✔
1152
{
1153
   // expression | expression : expression : expression
1154

1155
   BEGIN("mintypmax expression");
8✔
1156

1157
   return p_expression();
4✔
1158
}
1159

1160
static vlog_node_t p_concatenation(vlog_node_t head)
8✔
1161
{
1162
   // { expression { , expression } }
1163

1164
   BEGIN_WITH_HEAD("concatenation", head);
8✔
1165

1166
   if (head == NULL) {
8✔
1167
      consume(tLBRACE);
2✔
1168
      head = p_expression();
2✔
1169
   }
1170

1171
   vlog_node_t v = vlog_new(V_CONCAT);
8✔
1172
   vlog_add_param(v, head);
8✔
1173

1174
   while (optional(tCOMMA))
14✔
1175
      vlog_add_param(v, p_expression());
6✔
1176

1177
   consume(tRBRACE);
8✔
1178

1179
   vlog_set_loc(v, CURRENT_LOC);
8✔
1180
   return v;
8✔
1181
}
1182

1183
static vlog_node_t p_multiple_concatenation(vlog_node_t head)
2✔
1184
{
1185
   // { expression concatenation }
1186

1187
   BEGIN_WITH_HEAD("multiple concatenation", head);
2✔
1188

1189
   vlog_node_t v = p_concatenation(NULL);
2✔
1190
   vlog_set_value(v, head);
2✔
1191

1192
   consume(tRBRACE);
2✔
1193

1194
   vlog_set_loc(v, CURRENT_LOC);
2✔
1195
   return v;
2✔
1196
}
1197

1198
static vlog_node_t p_primary(void)
1,427✔
1199
{
1200
   // primary_literal | empty_queue
1201
   // | [ class_qualifier | package_scope ] hierarchical_identifier select
1202
   // | concatenation [ [ range_expression ] ]
1203
   // | multiple_concatenation [ [ range_expression ] ]
1204
   // | function_subroutine_call
1205
   // | let_expression | ( mintypmax_expression ) | cast
1206
   // | assignment_pattern_expression | streaming_concatenation
1207
   // | sequence_method_call | this | $ | null
1208

1209
   BEGIN("primary");
2,854✔
1210

1211
   switch (peek()) {
1,427✔
1212
   case tID:
636✔
1213
      return p_select(p_identifier());
636✔
1214
   case tSTRING:
742✔
1215
   case tNUMBER:
1216
   case tUNSIGNED:
1217
   case tREAL:
1218
      return p_primary_literal();
742✔
1219
   case tSYSTASK:
40✔
1220
      return p_subroutine_call(V_SYS_FCALL);
40✔
1221
   case tLPAREN:
1✔
1222
      {
1223
         consume(tLPAREN);
1✔
1224
         vlog_node_t expr = p_mintypmax_expression();
1✔
1225
         consume(tRPAREN);
1✔
1226
         return expr;
1✔
1227
      }
1228
   case tLBRACE:
8✔
1229
      {
1230
         consume(tLBRACE);
8✔
1231

1232
         vlog_node_t head = p_expression();
8✔
1233
         if (peek() == tLBRACE)
8✔
1234
            return p_multiple_concatenation(head);
2✔
1235
         else
1236
            return p_concatenation(head);
6✔
1237
      }
UNCOV
1238
   default:
×
UNCOV
1239
      one_of(tID, tSTRING, tNUMBER, tUNSIGNED, tREAL, tSYSTASK, tLPAREN,
×
1240
             tLBRACE);
UNCOV
1241
      return p_select(error_marker());
×
1242
   }
1243
}
1244

1245
static vlog_binary_t p_binary_operator(void)
213✔
1246
{
1247
   // + | - | * | / | % | == | != | === | !== | ==? | !=? | && | ||
1248
   //  | ** | < | <= | > | >= | & | | | ^ | ^~ | ~^ | >> | <<
1249
   //  | >>> | <<< | -> | <->
1250

1251
   BEGIN("binary operator");
426✔
1252

1253
   switch (one_of(tBAR, tPLUS, tAMP, tCASEEQ, tCASENEQ, tLOGOR,
213✔
1254
                  tLOGEQ, tLOGNEQ, tDBLAMP, tSHIFTLL, tSHIFTRL,
1255
                  tSHIFTLA, tSHIFTRA, tLT, tGT, tLE, tGE, tMINUS,
1256
                  tTIMES, tOVER, tPERCENT)) {
1257
   case tBAR:     return V_BINARY_OR;
1258
   case tAMP:     return V_BINARY_AND;
18✔
1259
   case tCASEEQ:  return V_BINARY_CASE_EQ;
14✔
1260
   case tCASENEQ: return V_BINARY_CASE_NEQ;
87✔
1261
   case tLOGEQ:   return V_BINARY_LOG_EQ;
9✔
UNCOV
1262
   case tLOGNEQ:  return V_BINARY_LOG_NEQ;
×
1263
   case tLOGOR:   return V_BINARY_LOG_OR;
17✔
1264
   case tDBLAMP:  return V_BINARY_LOG_AND;
4✔
1265
   case tSHIFTLL: return V_BINARY_SHIFT_LL;
1✔
1266
   case tSHIFTRL: return V_BINARY_SHIFT_RL;
1✔
1267
   case tSHIFTLA: return V_BINARY_SHIFT_LA;
1✔
1268
   case tSHIFTRA: return V_BINARY_SHIFT_RA;
1✔
1269
   case tLT:      return V_BINARY_LT;
7✔
1270
   case tGT:      return V_BINARY_GT;
7✔
1271
   case tLE:      return V_BINARY_LEQ;
6✔
1272
   case tGE:      return V_BINARY_GEQ;
6✔
1273
   case tMINUS:   return V_BINARY_MINUS;
1✔
1274
   case tTIMES:   return V_BINARY_TIMES;
2✔
1275
   case tOVER:    return V_BINARY_DIVIDE;
1✔
1276
   case tPERCENT: return V_BINARY_MOD;
1✔
1277
   case tPLUS:
17✔
1278
   default:       return V_BINARY_PLUS;
17✔
1279
   }
1280
}
1281

1282
static vlog_unary_t p_unary_operator(void)
41✔
1283
{
1284
   // + | - | ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~
1285

1286
   BEGIN("unary operator");
82✔
1287

1288
   switch (one_of(tMINUS, tPLUS, tTILDE, tBANG)) {
41✔
1289
   case tMINUS: return V_UNARY_NEG;
1290
   case tTILDE: return V_UNARY_BITNEG;
21✔
1291
   case tBANG: return V_UNARY_NOT;
17✔
UNCOV
1292
   case tPLUS:
×
UNCOV
1293
   default: return V_UNARY_IDENTITY;
×
1294
   }
1295
}
1296

1297
static vlog_incdec_t p_inc_or_dec_operator(void)
2✔
1298
{
1299
   // ++ | --
1300

1301
   BEGIN("inc or dec operator");
4✔
1302

1303
   switch (one_of(tPLUSPLUS, tMINUSMINUS)) {
2✔
1304
   case tMINUSMINUS: return V_INCDEC_MINUS;
1305
   case tPLUSPLUS:
1✔
1306
   default: return V_INCDEC_PLUS;
1✔
1307
   }
1308
}
1309

1310
static vlog_node_t p_inc_or_dec_expression(vlog_node_t head)
2✔
1311
{
1312
   // inc_or_dec_operator { attribute_instance } variable_lvalue
1313
   //   | variable_lvalue { attribute_instance } inc_or_dec_operator
1314

1315
   BEGIN_WITH_HEAD("inc or dec expression", head);
2✔
1316

1317
   vlog_node_t v = vlog_new(head ? V_POSTFIX : V_PREFIX);
3✔
1318
   vlog_set_subkind(v, p_inc_or_dec_operator());
2✔
1319
   vlog_set_target(v, head ?: p_variable_lvalue());
2✔
1320

1321
   vlog_set_loc(v, CURRENT_LOC);
2✔
1322
   return v;
2✔
1323
}
1324

1325
static vlog_node_t p_nonbinary_expression(void)
1,428✔
1326
{
1327
   // primary | unary_operator { attribute_instance } primary
1328
   //   | inc_or_dec_expression | ( operator_assignment )
1329
   //   | conditional_expression | inside_expression | tagged_union_expression
1330

1331
   switch (peek()) {
1,428✔
1332
   case tID:
1,386✔
1333
   case tSTRING:
1334
   case tNUMBER:
1335
   case tUNSIGNED:
1336
   case tREAL:
1337
   case tSYSTASK:
1338
   case tLPAREN:
1339
   case tLBRACE:
1340
      return p_primary();
1,386✔
1341
   case tMINUS:
41✔
1342
   case tTILDE:
1343
   case tBANG:
1344
      {
1345
         vlog_node_t v = vlog_new(V_UNARY);
41✔
1346
         vlog_set_subkind(v, p_unary_operator());
41✔
1347
         vlog_set_value(v, p_primary());
41✔
1348
         vlog_set_loc(v, CURRENT_LOC);
41✔
1349
         return v;
41✔
1350
      }
UNCOV
1351
   case tPLUSPLUS:
×
1352
   case tMINUSMINUS:
UNCOV
1353
      return p_inc_or_dec_expression(NULL);
×
1354
   default:
1✔
1355
      one_of(tID, tSTRING, tNUMBER, tUNSIGNED, tREAL, tSYSTASK, tLPAREN,
1✔
1356
             tLBRACE, tMINUS, tTILDE, tBANG, tPLUSPLUS, tMINUSMINUS);
1357
      return p_select(error_marker());
1✔
1358
   }
1359
}
1360

1361
static vlog_node_t p_conditional_expression(vlog_node_t head)
2✔
1362
{
1363
   // cond_predicate ? { attribute_instance } expression : expression
1364

1365
   BEGIN("conditional expression");
2✔
1366

1367
   vlog_node_t v = vlog_new(V_COND_EXPR);
2✔
1368
   vlog_set_value(v, head);
2✔
1369

1370
   consume(tQUESTION);
2✔
1371

1372
   while (peek() == tATTRBEGIN)
2✔
UNCOV
1373
      p_attribute_instance();
×
1374

1375
   vlog_set_left(v, p_expression());
2✔
1376

1377
   consume(tCOLON);
2✔
1378

1379
   vlog_set_right(v, p_expression());
2✔
1380

1381
   vlog_set_loc(v, CURRENT_LOC);
2✔
1382
   return v;
2✔
1383
}
1384

1385
static bool peek_binary_operator(int *prec)
1,693✔
1386
{
1387
   // See LRM 1800-2017 section 11.3.2 for operator precedence table
1388

1389
   switch (peek()) {
1,693✔
1390
   case tTIMES:
7✔
1391
   case tOVER:
1392
   case tPERCENT:  *prec = 11; return true;
7✔
1393
   case tPLUS:
22✔
1394
   case tMINUS:    *prec = 10; return true;
22✔
1395
   case tSHIFTLL:
4✔
1396
   case tSHIFTRL:
1397
   case tSHIFTLA:
1398
   case tSHIFTRA:  *prec = 9;  return true;
4✔
1399
   case tLT:
26✔
1400
   case tGT:
1401
   case tLE:
1402
   case tGE:       *prec = 8;  return true;
26✔
1403
   case tCASEEQ:
131✔
1404
   case tCASENEQ:
1405
   case tLOGEQ:
1406
   case tLOGNEQ:   *prec = 7;  return true;
131✔
1407
   case tAMP:      *prec = 6;  return true;
19✔
1408
   case tBAR:      *prec = 4;  return true;
13✔
1409
   case tDBLAMP:   *prec = 3;  return true;
7✔
1410
   case tLOGOR:    *prec = 2;  return true;
33✔
1411
   case tQUESTION: *prec = 1;  return true;
2✔
1412
   default:
1413
      return false;
1414
   }
1415
}
1416

1417
static vlog_node_t p_binary_expression(vlog_node_t lhs, int min_prec)
1,240✔
1418
{
1419
   // Precedence climbing method, see
1420
   //    https://en.wikipedia.org/wiki/Operator-precedence_parser
1421

1422
   int prec1;
1,240✔
1423
   while (peek_binary_operator(&prec1) && prec1 >= min_prec) {
1,455✔
1424
      if (peek() == tQUESTION)
215✔
1425
         lhs = p_conditional_expression(lhs);
2✔
1426
      else {
1427
         vlog_node_t v = vlog_new(V_BINARY);
213✔
1428
         vlog_set_subkind(v, p_binary_operator());
213✔
1429
         vlog_set_left(v, lhs);
213✔
1430

1431
         vlog_node_t rhs = p_nonbinary_expression();
213✔
1432

1433
         int prec2;
213✔
1434
         while (peek_binary_operator(&prec2) && prec2 > prec1)
238✔
1435
            rhs = p_binary_expression(rhs, prec1 + (prec2 > prec1));
25✔
1436

1437
         vlog_set_right(v, rhs);
213✔
1438
         vlog_set_loc(v, CURRENT_LOC);
213✔
1439
         lhs = v;
213✔
1440
      }
1441
   }
1442

1443
   return lhs;
1,240✔
1444
}
1445

1446
static vlog_node_t p_expression(void)
1,215✔
1447
{
1448
   // primary | unary_operator { attribute_instance } primary
1449
   //   | inc_or_dec_expression | ( operator_assignment )
1450
   //   | expression binary_operator { attribute_instance } expression
1451
   //   | conditional_expression | inside_expression | tagged_union_expression
1452

1453
   BEGIN("expression");
2,430✔
1454

1455
   vlog_node_t head = p_nonbinary_expression();
1,215✔
1456
   return p_binary_expression(head, 0);
1,215✔
1457
}
1458

1459
static void p_event_expression(vlog_node_t ctrl)
71✔
1460
{
1461
   // [ edge_identifier ] expression [ iff expression ]
1462
   //   | sequence_instance [ iff expression ]
1463
   //   | event_expression or event_expression
1464
   //   | event_expression , event_expression
1465
   //   | ( event_expression )
1466

1467
   BEGIN("event expression");
142✔
1468

1469
   do {
91✔
1470
      if (optional(tLPAREN)) {
91✔
1471
         p_event_expression(ctrl);
1✔
1472
         consume(tRPAREN);
1✔
1473
      }
1474
      else {
1475
         vlog_node_t v = vlog_new(V_EVENT);
90✔
1476

1477
         if (optional(tPOSEDGE))
90✔
1478
            vlog_set_subkind(v, V_EVENT_POSEDGE);
23✔
1479
         else if (optional(tNEGEDGE))
67✔
1480
            vlog_set_subkind(v, V_EVENT_NEGEDGE);
3✔
1481
         else
1482
            vlog_set_subkind(v, V_EVENT_LEVEL);
64✔
1483

1484
         vlog_set_value(v, p_expression());
90✔
1485
         vlog_set_loc(v, CURRENT_LOC);
90✔
1486

1487
         vlog_add_param(ctrl, v);
90✔
1488
      }
1489
   } while (optional(tOR) || optional(tCOMMA));
91✔
1490
}
71✔
1491

1492
static vlog_node_t p_cond_predicate(void)
126✔
1493
{
1494
   // expression_or_cond_pattern { &&& expression_or_cond_pattern }
1495

1496
   BEGIN("cond predicate");
252✔
1497

1498
   return p_expression();
126✔
1499
}
1500

1501
static vlog_node_t p_event_control(void)
70✔
1502
{
1503
   // @ hierarchical_event_identifier | @ ( event_expression )
1504
   //    | @* | @ (*) | @ ps_or_hierarchical_sequence_identifier
1505

1506
   BEGIN("event control");
70✔
1507

1508
   consume(tAT);
70✔
1509
   consume(tLPAREN);
70✔
1510

1511
   vlog_node_t v = vlog_new(V_EVENT_CONTROL);
70✔
1512

1513
   p_event_expression(v);
70✔
1514

1515
   consume(tRPAREN);
70✔
1516

1517
   vlog_set_loc(v, CURRENT_LOC);
70✔
1518
   return v;
70✔
1519
}
1520

1521
static vlog_node_t p_delay_value(void)
183✔
1522
{
1523
   // unsigned_number | real_number | ps_identifier | time_literal | 1step
1524

1525
   BEGIN("delay value");
366✔
1526

1527
   return p_unsigned_number();
183✔
1528
}
1529

1530
static vlog_node_t p_delay_control(void)
183✔
1531
{
1532
   // # delay_value | # ( mintypmax_expression )
1533

1534
   BEGIN("delay control");
183✔
1535

1536
   consume(tHASH);
183✔
1537

1538
   vlog_node_t v = vlog_new(V_DELAY_CONTROL);
183✔
1539
   vlog_set_value(v, p_delay_value());
183✔
1540
   vlog_set_loc(v, CURRENT_LOC);
183✔
1541
   return v;
183✔
1542
}
1543

1544
static vlog_node_t p_delay_or_event_control(void)
38✔
1545
{
1546
   // delay_control | event_control | repeat ( expression ) event_control
1547

1548
   BEGIN("delay or event control");
76✔
1549

1550
   return p_delay_control();
38✔
1551
}
1552

1553
static vlog_node_t p_variable_lvalue(void)
287✔
1554
{
1555
   // [ implicit_class_handle . | package_scope ]
1556
   //      hierarchical_variable_identifier select
1557
   //   | { variable_lvalue { , variable_lvalue } }
1558
   //   | [ assignment_pattern_expression_type ]
1559
   //      assignment_pattern_variable_lvalue
1560
   //   | streaming_concatenation
1561

1562
   BEGIN("variable lvalue");
287✔
1563

1564
   ident_t id = p_identifier();
287✔
1565
   vlog_node_t v = p_select(id);
287✔
1566

1567
   vlog_set_loc(v, CURRENT_LOC);
287✔
1568
   return v;
287✔
1569
}
1570

1571
static vlog_node_t p_net_lvalue(void)
121✔
1572
{
1573
   // ps_or_hierarchical_net_identifier constant_select
1574
   //   | { net_lvalue { , net_lvalue } }
1575
   //   | [ assignment_pattern_expression_type ] assignment_pattern_net_lvalue
1576

1577
   BEGIN("net lvalue");
242✔
1578

1579
   if (optional(tLBRACE)) {
121✔
1580
      vlog_node_t v = vlog_new(V_CONCAT);
3✔
1581

1582
      do {
6✔
1583
         vlog_add_param(v, p_net_lvalue());
6✔
1584
      } while (optional(tCOMMA));
6✔
1585

1586
      consume(tRBRACE);
3✔
1587

1588
      vlog_set_loc(v, CURRENT_LOC);
3✔
1589
      return v;
3✔
1590
   }
1591
   else {
1592
      ident_t id = p_identifier();
118✔
1593
      vlog_node_t v = p_constant_select(id);
118✔
1594

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

1600
static vlog_node_t p_operator_assignment(vlog_node_t lhs)
177✔
1601
{
1602
   // variable_lvalue assignment_operator expression
1603

1604
   BEGIN_WITH_HEAD("operator assignment", lhs);
177✔
1605

1606
   consume(tEQ);
177✔
1607

1608
   vlog_node_t v = vlog_new(V_BASSIGN);
177✔
1609
   vlog_set_target(v, lhs);
177✔
1610

1611
   vlog_set_value(v, p_expression());
177✔
1612

1613
   vlog_set_loc(v, CURRENT_LOC);
177✔
1614
   return v;
177✔
1615
}
1616

1617
static vlog_node_t p_blocking_assignment(vlog_node_t lhs)
201✔
1618
{
1619
   // variable_lvalue = delay_or_event_control expression
1620
   //   | nonrange_variable_lvalue = dynamic_array_new
1621
   //   | [ implicit_class_handle . | class_scope | package_scope ]
1622
   //         hierarchical_variable_identifier select != class_new
1623
   //   | operator_assignment
1624

1625
   BEGIN_WITH_HEAD("blocking assignment", lhs);
402✔
1626

1627
   switch (peek_nth(2)) {
201✔
1628
   case tHASH:
25✔
1629
   case tAT:
1630
      {
1631
         consume(tEQ);
25✔
1632

1633
         vlog_node_t v = vlog_new(V_BASSIGN);
25✔
1634
         vlog_set_target(v, lhs);
25✔
1635
         vlog_set_delay(v, p_delay_or_event_control());
25✔
1636
         vlog_set_value(v, p_expression());
25✔
1637

1638
         vlog_set_loc(v, CURRENT_LOC);
25✔
1639
         return v;
25✔
1640
      }
1641
   default:
176✔
1642
      return p_operator_assignment(lhs);
176✔
1643
   }
1644
}
1645

1646
static vlog_node_t p_nonblocking_assignment(vlog_node_t lhs)
82✔
1647
{
1648
   // variable_lvalue <= [ delay_or_event_control ] expression
1649

1650
   BEGIN_WITH_HEAD("non-blocking assignment", lhs);
82✔
1651

1652
   consume(tLE);
82✔
1653

1654
   vlog_node_t v = vlog_new(V_NBASSIGN);
82✔
1655
   vlog_set_target(v, lhs);
82✔
1656

1657
   if (scan(tHASH, tAT))
82✔
1658
      vlog_set_delay(v, p_delay_or_event_control());
13✔
1659

1660
   vlog_set_value(v, p_expression());
82✔
1661

1662
   vlog_set_loc(v, CURRENT_LOC);
82✔
1663
   return v;
82✔
1664
}
1665

1666
static vlog_node_t p_procedural_timing_control(void)
215✔
1667
{
1668
   // delay_control | event_control | cycle_delay
1669

1670
   BEGIN("procedural timing control");
430✔
1671

1672
   switch (peek()) {
215✔
1673
   case tAT:
70✔
1674
      return p_event_control();
70✔
1675
   case tHASH:
145✔
1676
      return p_delay_control();
145✔
UNCOV
1677
   default:
×
1678
      should_not_reach_here();
1679
   }
1680
}
1681

1682
static vlog_node_t p_procedural_timing_control_statement(void)
215✔
1683
{
1684
   // procedural_timing_control statement_or_null
1685

1686
   BEGIN("procedural timing control statement");
215✔
1687

1688
   vlog_node_t v = vlog_new(V_TIMING);
215✔
1689
   vlog_set_value(v, p_procedural_timing_control());
215✔
1690

1691
   vlog_node_t s = p_statement_or_null();
215✔
1692
   if (s != NULL)
215✔
1693
      vlog_add_stmt(v, s);
134✔
1694

1695
   vlog_set_loc(v, CURRENT_LOC);
215✔
1696
   return v;
215✔
1697
}
1698

1699
static vlog_node_t p_seq_block(void)
186✔
1700
{
1701
   // begin [ : block_identifier ] { block_item_declaration }
1702
   //   { statement_or_null } end [ : block_identifier ]
1703

1704
   BEGIN("sequential block");
186✔
1705

1706
   consume(tBEGIN);
186✔
1707

1708
   vlog_node_t v = vlog_new(V_SEQ_BLOCK);
186✔
1709

1710
   if (optional(tCOLON))
186✔
1711
      vlog_set_ident(v, p_identifier());
1✔
1712

1713
   while (not_at_token(tEND)) {
946✔
1714
      vlog_node_t s = p_statement_or_null();
760✔
1715
      if (s != NULL)
760✔
1716
         vlog_add_stmt(v, s);
760✔
1717
   }
1718

1719
   consume(tEND);
186✔
1720

1721
   vlog_set_loc(v, CURRENT_LOC);
186✔
1722
   return v;
186✔
1723
}
1724

1725
static vlog_node_t p_subroutine_call_statement(void)
390✔
1726
{
1727
   // subroutine_call ; | void ' ( function_subroutine_call ) ;
1728

1729
   BEGIN("subroutine call statement");
390✔
1730

1731
   vlog_node_t v = p_subroutine_call(V_SYS_TCALL);
390✔
1732

1733
   consume(tSEMI);
390✔
1734

1735
   vlog_set_loc(v, CURRENT_LOC);
390✔
1736
   return v;
390✔
1737
}
1738

1739
static vlog_node_t p_conditional_statement(void)
122✔
1740
{
1741
   // [ unique_priority ] if ( cond_predicate ) statement_or_null
1742
   //     { else if ( cond_predicate ) statement_or_null }
1743
   //     [ else statement_or_null ]
1744

1745
   BEGIN("conditional statement");
122✔
1746

1747
   vlog_node_t v = vlog_new(V_IF);
122✔
1748

1749
   consume(tIF);
122✔
1750
   consume(tLPAREN);
122✔
1751

1752
   vlog_node_t c0 = vlog_new(V_COND);
122✔
1753
   vlog_set_value(c0, p_cond_predicate());
122✔
1754
   vlog_add_cond(v, c0);
122✔
1755

1756
   consume(tRPAREN);
122✔
1757

1758
   vlog_node_t s0 = p_statement_or_null();
122✔
1759
   if (s0 != NULL)
122✔
1760
      vlog_add_stmt(c0, s0);
117✔
1761

1762
   bool stop = false;
1763
   while (!stop && optional(tELSE)) {
163✔
1764
      vlog_node_t c = vlog_new(V_COND);
41✔
1765
      vlog_add_cond(v, c);
41✔
1766

1767
      if (optional(tIF)) {
41✔
1768
         consume(tLPAREN);
4✔
1769
         vlog_set_value(c, p_cond_predicate());
4✔
1770
         consume(tRPAREN);
4✔
1771
      }
1772
      else
1773
         stop = true;
1774

1775
      vlog_node_t s = p_statement_or_null();
41✔
1776
      if (s != NULL)
41✔
1777
         vlog_add_stmt(c, s);
40✔
1778
   }
1779

1780
   vlog_set_loc(v, CURRENT_LOC);
122✔
1781
   return v;
122✔
1782
}
1783

1784
static vlog_node_t p_variable_assignment(vlog_kind_t kind)
1✔
1785
{
1786
   // variable_lvalue = expression
1787

1788
   BEGIN("variable assignment");
1✔
1789

1790
   vlog_node_t v = vlog_new(kind);
1✔
1791
   vlog_set_target(v, p_variable_lvalue());
1✔
1792

1793
   consume(tEQ);
1✔
1794

1795
   vlog_set_value(v, p_expression());
1✔
1796

1797
   vlog_set_loc(v, CURRENT_LOC);
1✔
1798
   return v;
1✔
1799
}
1800

1801
static void p_list_of_variable_assignments(vlog_node_t parent)
1✔
1802
{
1803
   // variable_assignment { , variable_assignment }
1804

1805
   BEGIN("list of variable assignments");
2✔
1806

1807
   do {
1✔
1808
      vlog_node_t v = p_variable_assignment(V_BASSIGN);
1✔
1809
      vlog_add_stmt(parent, v);
1✔
1810
   } while (optional(tCOMMA));
1✔
1811
}
1✔
1812

1813
static void p_for_variable_declaration(vlog_node_t parent)
2✔
1814
{
1815
   // [ var ] data_type variable_identifier = expression
1816
   //   { , variable_identifier = expression }
1817

1818
   BEGIN("for variable declaration");
4✔
1819

1820
   optional(tVAR);
2✔
1821

1822
   vlog_node_t dt = p_data_type();
2✔
1823

1824
   do {
2✔
1825
      vlog_node_t v = vlog_new(V_VAR_DECL);
2✔
1826
      vlog_set_ident(v, p_identifier());
2✔
1827
      vlog_set_type(v, dt);
2✔
1828

1829
      consume(tEQ);
2✔
1830

1831
      vlog_set_value(v, p_expression());
2✔
1832

1833
      vlog_set_loc(v, CURRENT_LOC);
2✔
1834
      vlog_add_decl(parent, v);
2✔
1835
   } while (optional(tCOMMA));
2✔
1836
}
2✔
1837

1838
static vlog_node_t p_for_initialization(void)
3✔
1839
{
1840
   // list_of_variable_assignments
1841
   //   | for_variable_declaration { , for_variable_declaration }
1842

1843
   BEGIN("for initialization");
3✔
1844

1845
   vlog_node_t v = vlog_new(V_FOR_INIT);
3✔
1846

1847
   if (scan(tREG, tSTRUCT, tUNION, tENUM, tSVINT, tINTEGER, tSVREAL,
3✔
1848
            tSHORTREAL, tREALTIME, tLOGIC, tVAR)) {
1849
      do {
2✔
1850
         p_for_variable_declaration(v);
2✔
1851
      } while (optional(tCOMMA));
2✔
1852
   }
1853
   else
1854
      p_list_of_variable_assignments(v);
1✔
1855

1856
   vlog_set_loc(v, CURRENT_LOC);
3✔
1857
   return v;
3✔
1858
}
1859

1860
static vlog_node_t p_for_step(void)
3✔
1861
{
1862
   // operator_assignment | inc_or_dec_expression | function_subroutine_call
1863

1864
   BEGIN("for step");
3✔
1865

1866
   vlog_node_t v = vlog_new(V_FOR_STEP);
3✔
1867

1868
   switch (peek()) {
3✔
1869
   case tPLUSPLUS:
1✔
1870
   case tMINUSMINUS:
1871
      vlog_add_stmt(v, p_inc_or_dec_expression(NULL));
1✔
1872
      break;
1✔
1873
   default:
2✔
1874
      {
1875
         vlog_node_t head = p_variable_lvalue();
2✔
1876

1877
         switch (peek()) {
2✔
1878
         case tPLUSPLUS:
1✔
1879
         case tMINUSMINUS:
1880
            vlog_add_stmt(v, p_inc_or_dec_expression(head));
1✔
1881
            break;
1✔
1882
         default:
1✔
1883
            vlog_add_stmt(v, p_operator_assignment(head));
1✔
1884
            break;
1✔
1885
         }
1886
      }
1887
      break;
1888
   }
1889

1890
   vlog_set_loc(v, CURRENT_LOC);
3✔
1891
   return v;
3✔
1892
}
1893

1894
static vlog_node_t p_loop_statement(void)
13✔
1895
{
1896
   // forever statement_or_null
1897
   //   | repeat ( expression ) statement_or_null
1898
   //   | while ( expression ) statement_or_null
1899
   //   | for ( [ for_initialization ] ; [ expression ] ; [ for_step ] )
1900
   //       statement_or_null
1901
   //   | do statement_or_null while ( expression ) ;
1902
   //   | foreach ( ps_or_hierarchical_array_identifier [ loop_variables ] )
1903
   //       statement
1904

1905
   BEGIN("loop statement");
26✔
1906

1907
   switch (one_of(tFOREVER, tWHILE, tREPEAT, tDO, tFOR)) {
13✔
1908
   case tFOREVER:
3✔
1909
      {
1910
         vlog_node_t v = vlog_new(V_FOREVER);
3✔
1911

1912
         vlog_node_t s = p_statement_or_null();
3✔
1913
         if (s != NULL)
3✔
1914
            vlog_add_stmt(v, s);
3✔
1915

1916
         vlog_set_loc(v, CURRENT_LOC);
3✔
1917
         return v;
3✔
1918
      }
1919

1920
   case tWHILE:
2✔
1921
      {
1922
         vlog_node_t v = vlog_new(V_WHILE);
2✔
1923

1924
         consume(tLPAREN);
2✔
1925
         vlog_set_value(v, p_expression());
2✔
1926
         consume(tRPAREN);
2✔
1927

1928
         vlog_node_t s = p_statement_or_null();
2✔
1929
         if (s != NULL)
2✔
UNCOV
1930
            vlog_add_stmt(v, s);
×
1931

1932
         vlog_set_loc(v, CURRENT_LOC);
2✔
1933
         return v;
2✔
1934
      }
1935

1936
   case tREPEAT:
2✔
1937
      {
1938
         vlog_node_t v = vlog_new(V_REPEAT);
2✔
1939

1940
         consume(tLPAREN);
2✔
1941
         vlog_set_value(v, p_expression());
2✔
1942
         consume(tRPAREN);
2✔
1943

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

1948
         vlog_set_loc(v, CURRENT_LOC);
2✔
1949
         return v;
2✔
1950
      }
1951

1952
   case tDO:
2✔
1953
      {
1954
         vlog_node_t v = vlog_new(V_DO_WHILE);
2✔
1955

1956
         vlog_node_t s = p_statement_or_null();
2✔
1957
         if (s != NULL)
2✔
1958
            vlog_add_stmt(v, s);
2✔
1959

1960
         consume(tWHILE);
2✔
1961

1962
         consume(tLPAREN);
2✔
1963
         vlog_set_value(v, p_expression());
2✔
1964
         consume(tRPAREN);
2✔
1965
         consume(tSEMI);
2✔
1966

1967
         vlog_set_loc(v, CURRENT_LOC);
2✔
1968
         return v;
2✔
1969
      }
1970

1971
   case tFOR:
4✔
1972
      {
1973
         vlog_node_t v = vlog_new(V_FOR_LOOP);
4✔
1974

1975
         consume(tLPAREN);
4✔
1976

1977
         if (not_at_token(tSEMI))
4✔
1978
            vlog_set_left(v, p_for_initialization());
3✔
1979
         else
1980
            vlog_set_left(v, vlog_new(V_FOR_INIT));
1✔
1981

1982
         consume(tSEMI);
4✔
1983

1984
         if (not_at_token(tSEMI))
4✔
1985
            vlog_set_value(v, p_expression());
2✔
1986

1987
         consume(tSEMI);
4✔
1988

1989
         if (not_at_token(tRPAREN))
4✔
1990
            vlog_set_right(v, p_for_step());
3✔
1991
         else
1992
            vlog_set_right(v, vlog_new(V_FOR_STEP));
1✔
1993

1994
         consume(tRPAREN);
4✔
1995

1996
         vlog_node_t s = p_statement_or_null();
4✔
1997
         if (s != NULL)
4✔
1998
            vlog_add_stmt(v, s);
1✔
1999

2000
         vlog_set_loc(v, CURRENT_LOC);
4✔
2001
         return v;
4✔
2002
      }
2003

UNCOV
2004
   default:
×
2005
      should_not_reach_here();
2006
   }
2007
}
2008

2009
static vlog_node_t p_wait_statement(void)
1✔
2010
{
2011
   // wait ( expression ) statement_or_null
2012
   //   | wait fork ;
2013
   //   | wait_order ( hierarchical_identifier { , hierarchical_identifier } )
2014
   //       action_block
2015

2016
   BEGIN("wait statement");
1✔
2017

2018
   consume(tWAIT);
1✔
2019

2020
   vlog_node_t v = vlog_new(V_WAIT);
1✔
2021

2022
   consume(tLPAREN);
1✔
2023

2024
   vlog_set_value(v, p_expression());
1✔
2025

2026
   consume(tRPAREN);
1✔
2027

2028
   vlog_node_t s = p_statement_or_null();
1✔
2029
   if (s != NULL)
1✔
2030
      vlog_add_stmt(v, s);
1✔
2031

2032
   vlog_set_loc(v, CURRENT_LOC);
1✔
2033
   return v;
1✔
2034
}
2035

2036
static vlog_node_t p_statement_item(void)
1,210✔
2037
{
2038
   // blocking_assignment ; | nonblocking_assignment ;
2039
   //   | procedural_continuous_assignment ; | case_statement
2040
   //   | conditional_statement | inc_or_dec_expression ;
2041
   //   | subroutine_call_statement | disable_statement
2042
   //   | event_trigger | loop_statement | jump_statement
2043
   //   | par_block | procedural_timing_control_statement
2044
   //   | seq_block | wait_statement | procedural_assertion_statement
2045
   //   | clocking_drive ; | randsequence_statement | randcase_statement
2046
   //   | expect_property_statement
2047

2048
   BEGIN("statement item");
2,420✔
2049

2050
   switch (peek()) {
1,210✔
2051
   case tID:
283✔
2052
      {
2053
         vlog_node_t lhs = p_variable_lvalue(), v = NULL;
283✔
2054

2055
         if (peek() == tLE)
283✔
2056
            v = p_nonblocking_assignment(lhs);
82✔
2057
         else
2058
            v = p_blocking_assignment(lhs);
201✔
2059

2060
         consume(tSEMI);
283✔
2061
         return v;
283✔
2062
      }
2063
   case tAT:
215✔
2064
   case tHASH:
2065
      return p_procedural_timing_control_statement();
215✔
2066
   case tBEGIN:
186✔
2067
      return p_seq_block();
186✔
2068
   case tSYSTASK:
390✔
2069
      return p_subroutine_call_statement();
390✔
2070
   case tIF:
122✔
2071
      return p_conditional_statement();
122✔
2072
   case tFOREVER:
13✔
2073
   case tWHILE:
2074
   case tREPEAT:
2075
   case tDO:
2076
   case tFOR:
2077
      return p_loop_statement();
13✔
2078
   case tWAIT:
1✔
2079
      return p_wait_statement();
1✔
UNCOV
2080
   default:
×
UNCOV
2081
      one_of(tID, tAT, tHASH, tBEGIN, tSYSTASK, tIF, tFOREVER, tWHILE, tREPEAT,
×
2082
             tDO, tFOR, tWAIT);
UNCOV
2083
      drop_tokens_until(tSEMI);
×
UNCOV
2084
      return NULL;
×
2085
   }
2086
}
2087

2088
static vlog_node_t p_statement(void)
1,210✔
2089
{
2090
   // [ block_identifier : ] { attribute_instance } statement_item
2091

2092
   BEGIN("statement");
2,420✔
2093

2094
   while (peek() == tATTRBEGIN)
1,210✔
UNCOV
2095
      p_attribute_instance();
×
2096

2097
   vlog_node_t s = p_statement_item();
1,210✔
2098
   if (s == NULL)
1,210✔
UNCOV
2099
      return vlog_new(V_SEQ_BLOCK);
×
2100

2101
   return s;
2102
}
2103

2104
static vlog_node_t p_statement_or_null(void)
1,229✔
2105
{
2106
   // statement | { attribute_instance } ;
2107

2108
   BEGIN("statement or null");
2,458✔
2109

2110
   if (optional(tSEMI))
1,229✔
2111
      return NULL;
2112
   else
2113
      return p_statement();
1,137✔
2114
}
2115

2116
static vlog_node_t p_always_construct(void)
73✔
2117
{
2118
   // always_keyword statement
2119

2120
   BEGIN("always construct");
73✔
2121

2122
   consume(tALWAYS);
73✔
2123

2124
   vlog_node_t v = vlog_new(V_ALWAYS);
73✔
2125
   vlog_set_ident(v, ident_uniq("__always#line%d", yylloc.first_line));
73✔
2126
   vlog_add_stmt(v, p_statement());
73✔
2127

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

2132
static vlog_node_t p_initial_construct(void)
74✔
2133
{
2134
   // initial statement_or_null
2135

2136
   BEGIN("initial construct");
74✔
2137

2138
   consume(tINITIAL);
74✔
2139

2140
   vlog_node_t v = vlog_new(V_INITIAL);
74✔
2141
   vlog_set_ident(v, ident_uniq("__initial#line%d", yylloc.first_line));
74✔
2142

2143
   vlog_node_t s = p_statement_or_null();
74✔
2144
   if (s != NULL)
74✔
2145
      vlog_add_stmt(v, s);
74✔
2146

2147
   vlog_set_loc(v, CURRENT_LOC);
74✔
2148
   return v;
74✔
2149
}
2150

2151
static vlog_node_t p_net_assignment(void)
49✔
2152
{
2153
   // net_lvalue = expression
2154

2155
   BEGIN("net assignment");
49✔
2156

2157
   vlog_node_t v = vlog_new(V_ASSIGN);
49✔
2158
   vlog_set_target(v, p_net_lvalue());
49✔
2159
   vlog_set_ident(v, ident_uniq("__assign#line%d", state.last_loc.first_line));
49✔
2160

2161
   consume(tEQ);
49✔
2162

2163
   vlog_set_value(v, p_expression());
49✔
2164

2165
   vlog_set_loc(v, CURRENT_LOC);
49✔
2166
   return v;
49✔
2167
}
2168

2169
static void p_list_of_net_assignments(vlog_node_t mod)
49✔
2170
{
2171
   // net_assignment { , net_assignment }
2172

2173
   BEGIN("list of net assignments");
98✔
2174

2175
   do {
49✔
2176
      vlog_add_stmt(mod, p_net_assignment());
49✔
2177
   } while (optional(tCOMMA));
49✔
2178
}
49✔
2179

2180
static void p_continuous_assign(vlog_node_t mod)
49✔
2181
{
2182
   // assign [ drive_strength ] [ delay3 ] list_of_net_assignments ;
2183
   //   | assign [ delay_control ] list_of_variable_assignments ;
2184

2185
   BEGIN("continuous assignment");
98✔
2186

2187
   consume(tASSIGN);
49✔
2188

2189
   p_list_of_net_assignments(mod);
49✔
2190

2191
   consume(tSEMI);
49✔
2192
}
49✔
2193

2194
static vlog_net_kind_t p_net_type(void)
73✔
2195
{
2196
   // supply0 | supply1 | tri | triand | trior | trireg | tri0
2197
   //   | tri1 | uwire | wire | wand | wor
2198

2199
   BEGIN("net type");
146✔
2200

2201
   switch (one_of(tWIRE, tSUPPLY0, tSUPPLY1)) {
73✔
2202
   case tSUPPLY0: return V_NET_SUPPLY0;
2203
   case tSUPPLY1: return V_NET_SUPPLY1;
3✔
2204
   case tWIRE:
64✔
2205
   default: return V_NET_WIRE;
64✔
2206
   }
2207
}
2208

2209
static vlog_node_t p_net_decl_assignment(vlog_net_kind_t kind,
91✔
2210
                                         vlog_node_t datatype)
2211
{
2212
   // net_identifier { unpacked_dimension } [ = expression ]
2213

2214
   BEGIN("net declaration assignment");
91✔
2215

2216
   vlog_node_t v = vlog_new(V_NET_DECL);
91✔
2217
   vlog_set_subkind(v, kind);
91✔
2218
   vlog_set_type(v, datatype);
91✔
2219
   vlog_set_ident(v, p_identifier());
91✔
2220

2221
   if (optional(tEQ))
91✔
2222
      vlog_set_value(v, p_expression());
10✔
2223

2224
   vlog_set_loc(v, CURRENT_LOC);
91✔
2225
   return v;
91✔
2226
}
2227

2228
static void p_list_of_net_decl_assignments(vlog_node_t mod,
73✔
2229
                                           vlog_net_kind_t kind,
2230
                                           vlog_node_t datatype)
2231
{
2232
   // net_decl_assignment { , net_decl_assignment }
2233

2234
   BEGIN("list of net declaration assignments");
146✔
2235

2236
   do {
91✔
2237
      vlog_node_t v = p_net_decl_assignment(kind, datatype);
91✔
2238
      vlog_add_decl(mod, v);
91✔
2239
   } while (optional(tCOMMA));
91✔
2240
}
73✔
2241

2242
static void p_net_declaration(vlog_node_t mod)
73✔
2243
{
2244
   // net_type [ drive_strength | charge_strength ] [ vectored | scalared ]
2245
   //     data_type_or_implicit [ delay3 ] list_of_net_decl_assignments ;
2246
   //  | net_type_identifier [ delay_control ] list_of_net_decl_assignments ;
2247
   //  | interconnect implicit_data_type [ # delay_value ] net_identifier
2248
   //     { unpacked_dimension } [ , net_identifier { unpacked_dimension } ] ;
2249

2250
   BEGIN("net declaration");
146✔
2251

2252
   const vlog_net_kind_t kind = p_net_type();
73✔
2253

2254
   vlog_node_t dt = p_data_type_or_implicit();
73✔
2255
   p_list_of_net_decl_assignments(mod, kind, dt);
73✔
2256

2257
   consume(tSEMI);
73✔
2258
}
73✔
2259

2260
static vlog_node_t p_variable_decl_assignment(vlog_node_t datatype)
147✔
2261
{
2262
   // variable_identifier { variable_dimension } [ = expression ]
2263
   //   | dynamic_array_variable_identifier unsized_dimension
2264
   //       { variable_dimension } [ = dynamic_array_new ]
2265
   //   | class_variable_identifier [ = class_new ]
2266

2267
   BEGIN("variable declaration assignment");
147✔
2268

2269
   vlog_node_t v = vlog_new(V_VAR_DECL);
147✔
2270
   vlog_set_ident(v, p_identifier());
147✔
2271
   vlog_set_type(v, datatype);
147✔
2272

2273
   if (optional(tEQ))
147✔
2274
      vlog_set_value(v, p_expression());
7✔
2275

2276
   vlog_set_loc(v, CURRENT_LOC);
147✔
2277
   return v;
147✔
2278
}
2279

2280
static void p_list_of_variable_decl_assignments(vlog_node_t parent,
125✔
2281
                                                vlog_node_t datatype)
2282
{
2283
   // variable_decl_assignment { , variable_decl_assignment }
2284

2285
   BEGIN("list of variable declaration assignments");
250✔
2286

2287
   do {
147✔
2288
      vlog_add_decl(parent, p_variable_decl_assignment(datatype));
147✔
2289
   } while (optional(tCOMMA));
147✔
2290
}
125✔
2291

2292
static vlog_node_t p_type_declaration(void)
3✔
2293
{
2294
   // typedef data_type type_identifier { variable_dimension } ;
2295
   //   | typedef interface_instance_identifier constant_bit_select .
2296
   //       type_identifier type_identifier ;
2297
   //   | typedef [ enum | struct | union | class | interface class ]
2298
   //       type_identifier ;
2299

2300
   BEGIN("type declaration");
3✔
2301

2302
   consume(tTYPEDEF);
3✔
2303

2304
   vlog_node_t v = vlog_new(V_TYPE_DECL);
3✔
2305
   vlog_set_type(v, p_data_type());
3✔
2306
   vlog_set_ident(v, p_identifier());
3✔
2307

2308
   consume(tSEMI);
3✔
2309

2310
   vlog_set_loc(v, CURRENT_LOC);
3✔
2311
   return v;
3✔
2312
}
2313

2314
static void p_data_declaration(vlog_node_t mod)
119✔
2315
{
2316
   // [ const ] [ var ] [ lifetime ] data_type_or_implicit
2317
   //     list_of_variable_decl_assignments ;
2318
   //  | type_declaration | package_import_declaration | net_type_declaration
2319

2320
   BEGIN("data declaration");
238✔
2321

2322
   switch (peek()) {
119✔
2323
   case tTYPEDEF:
3✔
2324
      vlog_add_decl(mod, p_type_declaration());
3✔
2325
      break;
3✔
2326

2327
   default:
116✔
2328
      {
2329
         vlog_node_t dt = p_data_type_or_implicit();
116✔
2330
         p_list_of_variable_decl_assignments(mod, dt);
116✔
2331

2332
         consume(tSEMI);
116✔
2333
      }
2334
   }
2335
}
119✔
2336

2337
static v_port_kind_t p_port_direction(void)
3✔
2338
{
2339
   // input | output | inout | ref
2340

2341
   BEGIN("port direction");
6✔
2342

2343
   switch (one_of(tINPUT, tOUTPUT, tINOUT)) {
3✔
2344
   case tINPUT:  return V_PORT_INPUT;
2345
   case tOUTPUT: return V_PORT_OUTPUT;
1✔
UNCOV
2346
   case tINOUT:  return V_PORT_INOUT;
×
2347
   default:      return V_PORT_INPUT;
2348
   }
2349
}
2350

2351
static v_port_kind_t p_tf_port_direction(void)
3✔
2352
{
2353
   // port_direction | const ref
2354

2355
   BEGIN("task or function port direction");
6✔
2356

2357
   return p_port_direction();
3✔
2358
}
2359

2360
static vlog_node_t p_tf_port_item(void)
4✔
2361
{
2362
   // { attribute_instance } [ tf_port_direction ] [ var ]
2363
   //    data_type_or_implicit [ port_identifier { variable_dimension }
2364
   //    [ = expression ] ]
2365

2366
   BEGIN("task or function port item");
4✔
2367

2368
   vlog_node_t v = vlog_new(V_PORT_DECL);
4✔
2369

2370
   if (scan(tINPUT, tOUTPUT))
4✔
2371
      vlog_set_subkind(v, p_tf_port_direction());
3✔
2372
   else
2373
      vlog_set_subkind(v, V_PORT_INPUT);
1✔
2374

2375
   vlog_set_type(v, p_data_type_or_implicit());
4✔
2376

2377
   if (peek() == tID) {
4✔
2378
      vlog_set_ident(v, p_identifier());
4✔
2379

2380
      if (optional(tEQ))
4✔
UNCOV
2381
         vlog_set_value(v, p_expression());
×
2382
   }
2383

2384
   vlog_set_loc(v, CURRENT_LOC);
4✔
2385
   return v;
4✔
2386
}
2387

2388
static void p_tf_port_list(vlog_node_t tf)
2✔
2389
{
2390
   // tf_port_item { , tf_port_item }
2391

2392
   BEGIN("task or function port list");
4✔
2393

2394
   do {
4✔
2395
      p_tf_port_item();
4✔
2396
   } while (optional(tCOMMA));
4✔
2397
}
2✔
2398

2399
static void p_task_body_declaration(vlog_node_t task)
2✔
2400
{
2401
   // [ interface_identifier . | class_scope ] task_identifier ;
2402
   //    { tf_item_declaration } { statement_or_null }
2403
   //    endtask [ : task_identifier ]
2404
   // | [ interface_identifier . | class_scope ] task_identifier
2405
   //    ( [ tf_port_list ] ) ; { block_item_declaration }
2406
   //    { statement_or_null } endtask [ : task_identifier ]
2407

2408
   BEGIN("task body declaration");
4✔
2409

2410
   ident_t id = p_identifier();
2✔
2411
   vlog_set_ident(task, id);
2✔
2412

2413
   if (optional(tLPAREN)) {
2✔
2414
      p_tf_port_list(task);
1✔
2415
      consume(tRPAREN);
1✔
2416
   }
2417

2418
   consume(tSEMI);
2✔
2419

2420
   while (not_at_token(tENDTASK)) {
6✔
2421
      vlog_node_t s = p_statement_or_null();
2✔
2422
      if (s != NULL)
2✔
2423
         vlog_add_stmt(task, s);
2✔
2424
   }
2425

2426
   consume(tENDTASK);
2✔
2427
}
2✔
2428

2429
static vlog_node_t p_task_declaration(void)
2✔
2430
{
2431
   // task [ dynamic_override_specifiers ] [ lifetime ] task_body_declaration
2432

2433
   BEGIN("task declaration");
2✔
2434

2435
   vlog_node_t v = vlog_new(V_TASK_DECL);
2✔
2436

2437
   consume(tTASK);
2✔
2438

2439
   p_task_body_declaration(v);
2✔
2440

2441
   vlog_set_loc(v, CURRENT_LOC);
2✔
2442
   return v;
2✔
2443
}
2444

2445
static vlog_node_t p_function_data_type_or_implicit(void)
1✔
2446
{
2447
   // data_type_or_void | implicit_data_type
2448

2449
   BEGIN("function data type or implicit");
2✔
2450

2451
   return p_implicit_data_type();
1✔
2452
}
2453

2454
static void p_function_body_declaration(vlog_node_t func)
1✔
2455
{
2456
   // function_data_type_or_implicit [ interface_identifier . | class_scope ]
2457
   //    function_identifier ; { tf_item_declaration }
2458
   //    { function_statement_or_null } endfunction [ : function_identifier ]
2459
   // | function_data_type_or_implicit [ interface_identifier . | class_scope ]
2460
   //    function_identifier ( [ tf_port_list ] ) ; { block_item_declaration }
2461
   //    { function_statement_or_null } endfunction [ : function_identifier ]
2462

2463
   BEGIN("function body declaration");
2✔
2464

2465
   vlog_set_type(func, p_function_data_type_or_implicit());
1✔
2466

2467
   ident_t id = p_identifier();
1✔
2468
   vlog_set_ident(func, id);
1✔
2469

2470
   if (optional(tLPAREN)) {
1✔
2471
      p_tf_port_list(func);
1✔
2472
      consume(tRPAREN);
1✔
2473
   }
2474

2475
   consume(tSEMI);
1✔
2476

2477
   while (not_at_token(tENDFUNCTION)) {
3✔
2478
      vlog_node_t s = p_statement_or_null();
1✔
2479
      if (s != NULL)
1✔
2480
         vlog_add_stmt(func, s);
1✔
2481
   }
2482

2483
   consume(tENDFUNCTION);
1✔
2484
}
1✔
2485

2486
static vlog_node_t p_function_declaration(void)
1✔
2487
{
2488
   // function [ lifetime ] function_body_declaration
2489

2490
   BEGIN("function declaration");
1✔
2491

2492
   vlog_node_t v = vlog_new(V_FUNC_DECL);
1✔
2493

2494
   consume(tFUNCTION);
1✔
2495

2496
   p_function_body_declaration(v);
1✔
2497

2498
   vlog_set_loc(v, CURRENT_LOC);
1✔
2499
   return v;
1✔
2500
}
2501

2502
static vlog_node_t p_constant_param_expression(void)
3✔
2503
{
2504
   // mintypmax_expression | data_type | $
2505

2506
   BEGIN("constant parameter expression");
6✔
2507

2508
   return p_mintypmax_expression();
3✔
2509
}
2510

2511
static vlog_node_t p_param_assignment(vlog_node_t datatype)
3✔
2512
{
2513
   // parameter_identifier { unpacked_dimension }
2514
   //   [ = constant_param_expression ]
2515

2516
   BEGIN("parameter assignment");
3✔
2517

2518
   vlog_node_t v = vlog_new(V_PARAM_DECL);
3✔
2519
   vlog_set_ident(v, p_identifier());
3✔
2520

2521
   if (optional(tEQ))
3✔
2522
      vlog_set_value(v, p_constant_param_expression());
3✔
2523

2524
   vlog_set_loc(v, CURRENT_LOC);
3✔
2525
   return v;
3✔
2526
}
2527

2528
static void p_list_of_param_assignments(vlog_node_t parent,
3✔
2529
                                        vlog_node_t datatype)
2530
{
2531
   // param_assignment { , param_assignment }
2532

2533
   BEGIN("list of parameter assignments");
6✔
2534

2535
   do {
3✔
2536
      vlog_add_decl(parent, p_param_assignment(datatype));
3✔
2537
   } while (optional(tCOMMA));
3✔
2538
}
3✔
2539

2540
static void p_parameter_declaration(vlog_node_t mod)
3✔
2541
{
2542
   // parameter data_type_or_implicit list_of_param_assignments
2543

2544
   BEGIN("parameter declaration");
6✔
2545

2546
   consume(tPARAMETER);
3✔
2547

2548
   vlog_node_t dt = p_data_type_or_implicit();
3✔
2549
   p_list_of_param_assignments(mod, dt);
3✔
2550
}
3✔
2551

2552
static void p_package_or_generate_item_declaration(vlog_node_t mod)
198✔
2553
{
2554
   // net_declaration | data_declaration | task_declaration
2555
   //   | function_declaration | checker_declaration | dpi_import_export
2556
   //   | extern_constraint_declaration | class_declaration
2557
   //   | class_constructor_declaration | local_parameter_declaration ;
2558
   //   | parameter_declaration ; | covergroup_declaration
2559
   //   | overload_declaration | assertion_item_declaration | ;
2560

2561
   BEGIN("package or generate item declaration");
396✔
2562

2563
   switch (peek()) {
198✔
2564
   case tWIRE:
73✔
2565
   case tSUPPLY0:
2566
   case tSUPPLY1:
2567
      p_net_declaration(mod);
73✔
2568
      break;
73✔
2569
   case tREG:
119✔
2570
   case tSTRUCT:
2571
   case tUNION:
2572
   case tTYPEDEF:
2573
   case tENUM:
2574
   case tSVINT:
2575
   case tINTEGER:
2576
   case tSVREAL:
2577
   case tSHORTREAL:
2578
   case tREALTIME:
2579
      p_data_declaration(mod);
119✔
2580
      break;
119✔
2581
   case tTASK:
2✔
2582
      vlog_add_decl(mod, p_task_declaration());
2✔
2583
      break;
2✔
2584
   case tFUNCTION:
1✔
2585
      vlog_add_decl(mod, p_function_declaration());
1✔
2586
      break;
1✔
2587
   case tPARAMETER:
3✔
2588
      p_parameter_declaration(mod);
3✔
2589
      consume(tSEMI);
3✔
2590
      break;
3✔
UNCOV
2591
   default:
×
UNCOV
2592
      one_of(tWIRE, tSUPPLY0, tSUPPLY1, tREG, tSTRUCT, tUNION, tTYPEDEF,
×
2593
             tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTASK,
2594
             tFUNCTION, tPARAMETER);
UNCOV
2595
      drop_tokens_until(tSEMI);
×
UNCOV
2596
      break;
×
2597
   }
2598
}
198✔
2599

2600
static void p_module_or_generate_item_declaration(vlog_node_t mod)
198✔
2601
{
2602
   // package_or_generate_item_declaration | genvar_declaration
2603
   //   | clocking_declaration | default clocking clocking_identifier ;
2604
   //   | default disable iff expression_or_dist ;
2605

2606
   BEGIN("module or generate item declaration");
396✔
2607

2608
   p_package_or_generate_item_declaration(mod);
198✔
2609
}
198✔
2610

2611
static void p_module_common_item(vlog_node_t mod)
394✔
2612
{
2613
   // module_or_generate_item_declaration
2614
   //   | interface_instantiation | program_instantiation
2615
   //   | assertion_item | bind_directive | continuous_assign
2616
   //   | net_alias | initial_construct | final_construct
2617
   //   | always_construct | loop_generate_construct
2618
   //   | conditional_generate_construct | elaboration_system_task
2619

2620
   BEGIN("module common item");
788✔
2621

2622
   switch (peek()) {
394✔
2623
   case tALWAYS:
73✔
2624
      vlog_add_stmt(mod, p_always_construct());
73✔
2625
      break;
73✔
2626
   case tINITIAL:
74✔
2627
      vlog_add_stmt(mod, p_initial_construct());
74✔
2628
      break;
74✔
2629
   case tWIRE:
198✔
2630
   case tSUPPLY0:
2631
   case tSUPPLY1:
2632
   case tREG:
2633
   case tSTRUCT:
2634
   case tUNION:
2635
   case tTYPEDEF:
2636
   case tENUM:
2637
   case tSVINT:
2638
   case tINTEGER:
2639
   case tSVREAL:
2640
   case tSHORTREAL:
2641
   case tREALTIME:
2642
   case tTASK:
2643
   case tFUNCTION:
2644
   case tPARAMETER:
2645
      p_module_or_generate_item_declaration(mod);
198✔
2646
      break;
198✔
2647
   case tASSIGN:
49✔
2648
      p_continuous_assign(mod);
49✔
2649
      break;
49✔
UNCOV
2650
   default:
×
UNCOV
2651
      one_of(tALWAYS, tINITIAL, tWIRE, tSUPPLY0, tSUPPLY1, tREG, tSTRUCT,
×
2652
             tUNION, tTYPEDEF, tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL,
2653
             tREALTIME, tTASK, tFUNCTION, tPARAMETER, tASSIGN);
UNCOV
2654
      drop_tokens_until(tSEMI);
×
2655
   }
2656
}
394✔
2657

2658
static vlog_strength_t p_strength0(void)
4✔
2659
{
2660
   // supply0 | strong0 | pull0 | weak0
2661

2662
   BEGIN("strength0");
4✔
2663

2664
   switch (one_of(tSUPPLY0)) {
4✔
2665
   default:
2666
   case tSUPPLY0: return V_STRENGTH_SUPPLY;
4✔
2667
   }
2668
}
2669

2670
static vlog_strength_t p_strength1(void)
6✔
2671
{
2672
   // supply1 | strong1 | pull1 | weak1
2673

2674
   BEGIN("strength1");
6✔
2675

2676
   switch (one_of(tSUPPLY1)) {
6✔
2677
   default:
2678
   case tSUPPLY1: return V_STRENGTH_SUPPLY;
6✔
2679
   }
2680
}
2681

2682
static vlog_node_t p_pulldown_strength(void)
2✔
2683
{
2684
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength0 )
2685

2686
   BEGIN("pulldown strength");
2✔
2687

2688
   consume(tLPAREN);
2✔
2689

2690
   vlog_strength_t s0, s1;
2✔
2691
   switch (peek()) {
2✔
UNCOV
2692
   case tSUPPLY1:
×
UNCOV
2693
      s1 = p_strength1();
×
UNCOV
2694
      consume(tCOMMA);
×
UNCOV
2695
      s0 = p_strength0();
×
UNCOV
2696
      break;
×
2697
   default:
2✔
2698
      s0 = s1 = p_strength0();
2✔
2699
      if (optional(tCOMMA))
2✔
UNCOV
2700
         s1 = p_strength1();
×
2701
      break;
2702
   }
2703

2704
   consume(tRPAREN);
2✔
2705

2706
   vlog_node_t v = vlog_new(V_STRENGTH);
2✔
2707
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
2✔
2708
   vlog_set_loc(v, CURRENT_LOC);
2✔
2709
   return v;
2✔
2710
}
2711

2712
static vlog_node_t p_pullup_strength(void)
6✔
2713
{
2714
   // ( strength0 , strength1 ) | ( strength1 , strength0 ) | ( strength1 )
2715

2716
   BEGIN("pullup strength");
6✔
2717

2718
   consume(tLPAREN);
6✔
2719

2720
   vlog_strength_t s0, s1;
6✔
2721
   switch (peek()) {
6✔
2722
   case tSUPPLY0:
1✔
2723
      s0 = p_strength0();
1✔
2724
      consume(tCOMMA);
1✔
2725
      s1 = p_strength1();
1✔
2726
      break;
1✔
2727
   default:
5✔
2728
      s1 = s0 = p_strength1();
5✔
2729
      if (optional(tCOMMA))
5✔
2730
         s0 = p_strength0();
1✔
2731
      break;
2732
   }
2733

2734
   consume(tRPAREN);
6✔
2735

2736
   vlog_node_t v = vlog_new(V_STRENGTH);
6✔
2737
   vlog_set_subkind(v, MAKE_STRENGTH(s0, s1));
6✔
2738
   vlog_set_loc(v, CURRENT_LOC);
6✔
2739
   return v;
6✔
2740
}
2741

2742
static vlog_node_t p_pull_gate_instance(vlog_gate_kind_t kind, vlog_node_t st)
19✔
2743
{
2744
   // [ name_of_instance ] ( output_terminal )
2745

2746
   BEGIN("pull gate instance");
19✔
2747

2748
   vlog_node_t v = vlog_new(V_GATE_INST);
19✔
2749
   vlog_set_subkind(v, kind);
19✔
2750
   vlog_add_param(v, st);
19✔
2751

2752
   if (peek() == tID)
19✔
2753
      vlog_set_ident(v, p_identifier());
7✔
2754

2755
   consume(tLPAREN);
19✔
2756

2757
   vlog_set_target(v, p_net_lvalue());
19✔
2758

2759
   consume(tRPAREN);
19✔
2760

2761
   vlog_set_loc(v, CURRENT_LOC);
19✔
2762
   return v;
19✔
2763
}
2764

2765
static vlog_node_t p_n_terminal_gate_instance(vlog_gate_kind_t kind)
17✔
2766
{
2767
   // [ name_of_instance ] ( output_terminal , input_terminal
2768
   //     { , input_terminal } )
2769

2770
   BEGIN("N-terminal gate instance");
17✔
2771

2772
   vlog_node_t v = vlog_new(V_GATE_INST);
17✔
2773
   vlog_set_subkind(v, kind);
17✔
2774

2775
   if (peek() == tID)
17✔
2776
      vlog_set_ident(v, p_identifier());
2✔
2777

2778
   consume(tLPAREN);
17✔
2779

2780
   vlog_set_target(v, p_net_lvalue());
17✔
2781

2782
   consume(tCOMMA);
17✔
2783

2784
   do {
30✔
2785
      vlog_add_param(v, p_net_lvalue());
30✔
2786
   } while (optional(tCOMMA));
30✔
2787

2788
   consume(tRPAREN);
17✔
2789

2790
   vlog_set_loc(v, CURRENT_LOC);
17✔
2791
   return v;
17✔
2792
}
2793

2794
static void p_gate_instantiation(vlog_node_t mod)
36✔
2795
{
2796
   // cmos_switchtype [ delay3 ] cmos_switch_instance
2797
   //     { , cmos_switch_instance } ;
2798
   //  | enable_gatetype [ drive_strength ] [ delay3 ]
2799
   //     enable_gate_instance { , enable_gate_instance } ;
2800
   //  | mos_switchtype [ delay3 ] mos_switch_instance
2801
   //     { , mos_switch_instance } ;
2802
   //  | n_input_gatetype [ drive_strength ] [ delay2 ] n_input_gate_instance
2803
   //     { , n_input_gate_instance } ;
2804
   //  | n_output_gatetype [ drive_strength ] [ delay2 ] n_output_gate_instance
2805
   //     { , n_output_gate_instance } ;
2806
   //  | pass_en_switchtype [ delay2 ] pass_enable_switch_instance
2807
   //     { , pass_enable_switch_instance } ;
2808
   //  | pass_switchtype pass_switch_instance { , pass_switch_instance } ;
2809
   //  | pulldown [ pulldown_strength ] pull_gate_instance
2810
   //     { , pull_gate_instance } ;
2811
   //  | pullup [ pullup_strength ] pull_gate_instance
2812
   //     { , pull_gate_instance } ;
2813

2814
   BEGIN("gate instantiation");
72✔
2815

2816
   switch (one_of(tPULLDOWN, tPULLUP, tAND, tNAND, tOR, tNOR, tXOR, tXNOR,
36✔
2817
                  tNOT, tBUF)) {
2818
   case tPULLDOWN:
7✔
2819
      {
2820
         vlog_node_t st;
7✔
2821
         if (peek() == tLPAREN && peek_nth(2) != tID)
7✔
2822
            st = p_pulldown_strength();
2✔
2823
         else {
2824
            st = vlog_new(V_STRENGTH);
5✔
2825
            vlog_set_subkind(st, ST_PULLUP);
5✔
2826
         }
2827

2828
         do {
7✔
2829
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLDOWN, st);
7✔
2830
            vlog_add_stmt(mod, g);
7✔
2831
         } while (optional(tCOMMA));
7✔
2832
      }
2833
      break;
2834

2835
   case tPULLUP:
12✔
2836
      {
2837
         vlog_node_t st;
12✔
2838
         if (peek() == tLPAREN && peek_nth(2) != tID)
12✔
2839
            st = p_pullup_strength();
6✔
2840
         else {
2841
            st = vlog_new(V_STRENGTH);
6✔
2842
            vlog_set_subkind(st, ST_PULLUP);
6✔
2843
         }
2844

2845
         do {
12✔
2846
            vlog_node_t g = p_pull_gate_instance(V_GATE_PULLUP, st);
12✔
2847
            vlog_add_stmt(mod, g);
12✔
2848
         } while (optional(tCOMMA));
12✔
2849
      }
2850
      break;
2851

2852
   case tAND:
4✔
2853
      do {
4✔
2854
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_AND));
4✔
2855
      } while (optional(tCOMMA));
4✔
2856
      break;
2857

2858
   case tNAND:
3✔
2859
      do {
3✔
2860
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_NAND));
3✔
2861
      } while (optional(tCOMMA));
3✔
2862
      break;
2863

2864
   case tOR:
4✔
2865
      do {
4✔
2866
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_OR));
4✔
2867
      } while (optional(tCOMMA));
4✔
2868
      break;
2869

2870
   case tNOR:
×
2871
      do {
×
UNCOV
2872
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_NOR));
×
UNCOV
2873
      } while (optional(tCOMMA));
×
2874
      break;
2875

2876
   case tXOR:
3✔
2877
      do {
3✔
2878
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_XOR));
3✔
2879
      } while (optional(tCOMMA));
3✔
2880
      break;
2881

UNCOV
2882
   case tXNOR:
×
UNCOV
2883
      do {
×
UNCOV
2884
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_XNOR));
×
UNCOV
2885
      } while (optional(tCOMMA));
×
2886
      break;
2887

2888
   case tNOT:
3✔
2889
      do {
3✔
2890
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_NOT));
3✔
2891
      } while (optional(tCOMMA));
3✔
2892
      break;
2893

UNCOV
2894
   case tBUF:
×
UNCOV
2895
      do {
×
UNCOV
2896
         vlog_add_stmt(mod, p_n_terminal_gate_instance(V_GATE_BUF));
×
UNCOV
2897
      } while (optional(tCOMMA));
×
2898
      break;
2899

2900
   default:
2901
      break;
2902
   }
2903

2904
   consume(tSEMI);
36✔
2905
}
36✔
2906

2907
static void p_path_delay_expression(void)
3✔
2908
{
2909
   // constant_expression
2910
   //   | constant_expression : constant_expression : constant_expression
2911

2912
   BEGIN("path delay expression");
6✔
2913

2914
   (void)p_constant_expression();
3✔
2915
}
3✔
2916

2917
static void p_list_of_path_delay_expressions(void)
2✔
2918
{
2919
   // path_delay_expression { , path_delay_expression }
2920

2921
   BEGIN("list of path delay expressions");
4✔
2922

2923
   do {
3✔
2924
      p_path_delay_expression();
3✔
2925
   } while (optional(tCOMMA));
3✔
2926
}
2✔
2927

2928
static void p_path_delay_value(void)
2✔
2929
{
2930
   // list_of_path_delay_expressions | ( list_of_path_delay_expressions )
2931

2932
   BEGIN("path delay value");
4✔
2933

2934
   if (optional(tLPAREN)) {
2✔
2935
      p_list_of_path_delay_expressions();
1✔
2936
      consume(tRPAREN);
1✔
2937
   }
2938
   else
2939
      p_list_of_path_delay_expressions();
1✔
2940
}
2✔
2941

2942
static void p_specify_terminal_descriptor(void)
4✔
2943
{
2944
   // identifier [ [ constant_range_expression ] ]
2945

2946
   BEGIN("specify terminal descriptor");
8✔
2947

2948
   p_identifier();
4✔
2949
}
4✔
2950

2951
static void p_parallel_path_description(void)
2✔
2952
{
2953
   // ( specify_input_terminal_descriptor [ polarity_operator ] =>
2954
   //     specify_output_terminal_descriptor )
2955

2956
   BEGIN("parallel path description");
4✔
2957

2958
   consume(tLPAREN);
2✔
2959

2960
   p_specify_terminal_descriptor();
2✔
2961

2962
   consume(tASSOC);
2✔
2963

2964
   p_specify_terminal_descriptor();
2✔
2965

2966
   consume(tRPAREN);
2✔
2967
}
2✔
2968

2969
static void p_simple_path_declaration(void)
2✔
2970
{
2971
   // parallel_path_description = path_delay_value
2972
   //   | full_path_description = path_delay_value
2973

2974
   BEGIN("simple path declaration");
4✔
2975

2976
   p_parallel_path_description();
2✔
2977

2978
   consume(tEQ);
2✔
2979

2980
   p_path_delay_value();
2✔
2981
}
2✔
2982

2983
static void p_path_declaration(void)
2✔
2984
{
2985
   // simple_path_declaration ; | edge_sensitive_path_declaration ;
2986
   //   | state_dependent_path_declaration ;
2987

2988
   BEGIN("path declaration");
4✔
2989

2990
   p_simple_path_declaration();
2✔
2991

2992
   consume(tSEMI);
2✔
2993
}
2✔
2994

2995
static void p_specify_item(void)
2✔
2996
{
2997
   // specparam_declaration | pulsestyle_declaration | showcancelled_declaration
2998
   //   | path_declaration | system_timing_check
2999

3000
   BEGIN("specify item");
4✔
3001

3002
   switch (peek()) {
2✔
3003
   case tLPAREN:
2✔
3004
      p_path_declaration();
2✔
3005
      break;
2✔
UNCOV
3006
   default:
×
UNCOV
3007
      one_of(tLPAREN);
×
3008
   }
3009
}
2✔
3010

3011
static vlog_node_t p_specify_block(void)
1✔
3012
{
3013
   // specify { specify_item } endspecify
3014

3015
   BEGIN("specify block");
1✔
3016

3017
   consume(tSPECIFY);
1✔
3018

3019
   vlog_node_t v = vlog_new(V_SPECIFY);
1✔
3020

3021
   while (not_at_token(tENDSPECIFY))
3✔
3022
      p_specify_item();
2✔
3023

3024
   consume(tENDSPECIFY);
1✔
3025

3026
   vlog_set_loc(v, CURRENT_LOC);
1✔
3027
   return v;
1✔
3028
}
3029

3030
static vlog_node_t p_ordered_port_connection(void)
38✔
3031
{
3032
   // { attribute_instance } [ expression ]
3033

3034
   BEGIN("ordered port connection");
76✔
3035

3036
   return p_expression();
38✔
3037
}
3038

3039
static void p_list_of_port_connections(vlog_node_t inst)
17✔
3040
{
3041
   // ordered_port_connection { , ordered_port_connection }
3042
   //   | named_port_connection { , named_port_connection }
3043

3044
   BEGIN("list of port connections");
34✔
3045

3046
   do {
38✔
3047
      vlog_add_param(inst, p_ordered_port_connection());
38✔
3048
   } while (optional(tCOMMA));
38✔
3049
}
17✔
3050

3051
static vlog_node_t p_hierarchical_instance(ident_t module_id)
17✔
3052
{
3053
   // name_of_instance ( [ list_of_port_connections ] )
3054

3055
   BEGIN("hierarchical instance");
17✔
3056

3057
   vlog_node_t v = vlog_new(V_MOD_INST);
17✔
3058
   vlog_set_ident(v, p_identifier());
17✔
3059
   vlog_set_ident2(v, module_id);
17✔
3060

3061
   consume(tLPAREN);
17✔
3062

3063
   if (peek() != tRPAREN)
17✔
3064
      p_list_of_port_connections(v);
17✔
3065

3066
   consume(tRPAREN);
17✔
3067

3068
   vlog_set_loc(v, CURRENT_LOC);
17✔
3069
   return v;
17✔
3070
}
3071

3072
static void p_module_instantiation(vlog_node_t mod)
17✔
3073
{
3074
   // module_identifier [ parameter_value_assignment ] hierarchical_instance
3075
   //   { , hierarchical_instance } ;
3076

3077
   BEGIN("module instantiation");
34✔
3078

3079
   ident_t module_id = p_identifier();
17✔
3080

3081
   do {
17✔
3082
      vlog_add_stmt(mod, p_hierarchical_instance(module_id));
17✔
3083
   } while (optional(tCOMMA));
17✔
3084

3085
   consume(tSEMI);
17✔
3086
}
17✔
3087

3088
static void p_module_or_generate_item(vlog_node_t mod)
447✔
3089
{
3090
   // { attribute_instance } parameter_override
3091
   //   | { attribute_instance } gate_instantiation
3092
   //   | { attribute_instance } udp_instantiation
3093
   //   | { attribute_instance } module_instantiation
3094
   //   | { attribute_instance } module_common_item
3095

3096
   BEGIN("module or generate item");
894✔
3097

3098
   while (peek() == tATTRBEGIN)
453✔
3099
      p_attribute_instance();
6✔
3100

3101
   switch (peek()) {
447✔
3102
   case tALWAYS:
394✔
3103
   case tWIRE:
3104
   case tSUPPLY0:
3105
   case tSUPPLY1:
3106
   case tREG:
3107
   case tSTRUCT:
3108
   case tUNION:
3109
   case tASSIGN:
3110
   case tINITIAL:
3111
   case tTYPEDEF:
3112
   case tENUM:
3113
   case tSVINT:
3114
   case tINTEGER:
3115
   case tSVREAL:
3116
   case tSHORTREAL:
3117
   case tREALTIME:
3118
   case tTASK:
3119
   case tFUNCTION:
3120
   case tPARAMETER:
3121
      p_module_common_item(mod);
394✔
3122
      break;
394✔
3123
   case tPULLDOWN:
36✔
3124
   case tPULLUP:
3125
   case tAND:
3126
   case tNAND:
3127
   case tOR:
3128
   case tNOR:
3129
   case tXOR:
3130
   case tXNOR:
3131
   case tNOT:
3132
   case tBUF:
3133
      p_gate_instantiation(mod);
36✔
3134
      break;
36✔
3135
   case tID:
17✔
3136
      p_module_instantiation(mod);
17✔
3137
      break;
17✔
UNCOV
3138
   default:
×
UNCOV
3139
      one_of(tALWAYS, tWIRE, tSUPPLY0, tSUPPLY1, tREG, tSTRUCT, tUNION, tASSIGN,
×
3140
             tINITIAL, tTYPEDEF, tENUM, tSVINT, tINTEGER, tSVREAL, tSHORTREAL,
3141
             tREALTIME, tTASK, tFUNCTION, tPARAMETER, tPULLDOWN, tPULLUP, tID,
3142
             tAND, tNAND, tOR, tNOR, tXOR, tXNOR, tNOT, tBUF);
UNCOV
3143
      drop_tokens_until(tSEMI);
×
3144
   }
3145
}
447✔
3146

3147
static void p_non_port_module_item(vlog_node_t mod)
450✔
3148
{
3149
   // generate_region | module_or_generate_item | specify_block
3150
   //   | { attribute_instance } specparam_declaration | program_declaration
3151
   //   | module_declaration | interface_declaration | timeunits_declaration
3152

3153
   BEGIN("non-port module item");
900✔
3154

3155
   switch (peek()) {
450✔
3156
   case tALWAYS:
447✔
3157
   case tWIRE:
3158
   case tSUPPLY0:
3159
   case tSUPPLY1:
3160
   case tREG:
3161
   case tSTRUCT:
3162
   case tUNION:
3163
   case tASSIGN:
3164
   case tINITIAL:
3165
   case tPULLDOWN:
3166
   case tPULLUP:
3167
   case tID:
3168
   case tATTRBEGIN:
3169
   case tAND:
3170
   case tNAND:
3171
   case tOR:
3172
   case tNOR:
3173
   case tXOR:
3174
   case tXNOR:
3175
   case tNOT:
3176
   case tBUF:
3177
   case tTYPEDEF:
3178
   case tENUM:
3179
   case tSVINT:
3180
   case tINTEGER:
3181
   case tSVREAL:
3182
   case tSHORTREAL:
3183
   case tREALTIME:
3184
   case tTASK:
3185
   case tFUNCTION:
3186
   case tPARAMETER:
3187
      p_module_or_generate_item(mod);
447✔
3188
      break;
447✔
3189
   case tSPECIFY:
1✔
3190
      vlog_add_stmt(mod, p_specify_block());
1✔
3191
      break;
1✔
3192
   default:
2✔
3193
      one_of(tALWAYS, tWIRE, tSUPPLY0, tSUPPLY1, tREG, tSTRUCT, tUNION,
2✔
3194
             tASSIGN, tPULLDOWN, tPULLUP, tID, tATTRBEGIN, tAND, tNAND,
3195
             tOR, tNOR, tXOR, tXNOR, tNOT, tBUF, tTYPEDEF, tENUM, tSVINT,
3196
             tINTEGER, tSVREAL, tSHORTREAL, tREALTIME, tTASK, tFUNCTION,
3197
             tPARAMETER, tSPECIFY);
3198
      drop_tokens_until(tSEMI);
2✔
3199
   }
3200
}
450✔
3201

3202
static void p_module_item(vlog_node_t mod)
507✔
3203
{
3204
   // port_declaration ; | non_port_module_item
3205

3206
   BEGIN("module item");
1,014✔
3207

3208
   if (scan(tINOUT, tINPUT, tOUTPUT)) {
507✔
3209
      p_port_declaration(mod);
57✔
3210
      consume(tSEMI);
57✔
3211
   }
3212
   else
3213
      p_non_port_module_item(mod);
450✔
3214
}
507✔
3215

3216
static void p_ansi_port_declaration(vlog_node_t mod, v_port_kind_t *kind,
53✔
3217
                                    bool *isreg)
3218
{
3219
   // [ net_port_header | interface_port_header ] port_identifier
3220
   //     { unpacked_dimension } [ = constant_expression ]
3221
   // | [ variable_port_header ] port_identifier { variable_dimension }
3222
   //     [ = constant_expression ]
3223
   // | [ port_direction ] . port_identifier ( [ expression ] )
3224

3225
   BEGIN("ANSI port declaration");
106✔
3226

3227
   vlog_node_t dt;
53✔
3228
   if (peek() != tID)
53✔
3229
      dt = p_net_port_header(kind, isreg);
36✔
3230
   else
3231
      dt = logic_type();
17✔
3232

3233
   ident_t id, ext;
53✔
3234
   p_external_identifier(&id, &ext);
53✔
3235

3236
   vlog_node_t v = vlog_new(V_PORT_DECL);
53✔
3237
   vlog_set_subkind(v, *kind);
53✔
3238
   vlog_set_ident(v, id);
53✔
3239
   vlog_set_ident2(v, ext);
53✔
3240
   vlog_set_type(v, dt);
53✔
3241
   vlog_set_loc(v, &state.last_loc);
53✔
3242

3243
   vlog_add_decl(mod, v);
53✔
3244

3245
   if (*isreg) {
53✔
3246
      vlog_node_t reg = vlog_new(V_VAR_DECL);
10✔
3247
      vlog_set_loc(reg, CURRENT_LOC);
10✔
3248
      vlog_set_ident(reg, id);
10✔
3249
      vlog_set_type(reg, dt);
10✔
3250

3251
      vlog_add_decl(mod, reg);
10✔
3252
   }
3253

3254
   vlog_node_t ref = vlog_new(V_REF);
53✔
3255
   vlog_set_loc(ref, CURRENT_LOC);
53✔
3256
   vlog_set_ident(ref, id);
53✔
3257
   vlog_set_ref(ref, v);
53✔
3258

3259
   vlog_add_port(mod, ref);
53✔
3260
}
53✔
3261

3262
static void p_list_of_port_declarations(vlog_node_t mod)
17✔
3263
{
3264
   // ( [ { attribute_instance } ansi_port_declaration
3265
   //   { , { attribute_instance } ansi_port_declaration } ] )
3266

3267
   BEGIN("list of port declarations");
34✔
3268

3269
   consume(tLPAREN);
17✔
3270

3271
   if (peek() != tRPAREN) {
17✔
3272
      v_port_kind_t kind = V_PORT_INPUT;
14✔
3273
      bool isreg = false;
14✔
3274
      do {
53✔
3275
         p_ansi_port_declaration(mod, &kind, &isreg);
53✔
3276
      } while (optional(tCOMMA));
53✔
3277
   }
3278

3279
   consume(tRPAREN);
17✔
3280
}
17✔
3281

3282
static void p_module_ansi_header(vlog_node_t mod)
90✔
3283
{
3284
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
3285
   //    { package_import_declaration } [ parameter_port_list ]
3286
   ///   [ list_of_port_declarations ] ;
3287

3288
   EXTEND("module ANSI header");
180✔
3289

3290
   if (peek() == tLPAREN)
90✔
3291
      p_list_of_port_declarations(mod);
17✔
3292

3293
   consume(tSEMI);
90✔
3294

3295
   vlog_set_loc(mod, CURRENT_LOC);
90✔
3296
}
90✔
3297

3298
static vlog_node_t p_port_reference(void)
64✔
3299
{
3300
   // port_identifier constant_select
3301

3302
   BEGIN("port reference");
128✔
3303

3304
   return p_constant_select(p_identifier());
64✔
3305
}
3306

3307
static vlog_node_t p_port_expression(void)
64✔
3308
{
3309
   // port_reference | { port_reference { , port_reference } }
3310

3311
   BEGIN("port expression");
128✔
3312

3313
   return p_port_reference();
64✔
3314
}
3315

3316
static vlog_node_t p_port(void)
64✔
3317
{
3318
   // [ port_expression ] | . port_identifier ( [ port_expression ] )
3319

3320
   BEGIN("port");
128✔
3321

3322
   return p_port_expression();
64✔
3323
}
3324

3325
static void p_list_of_ports(vlog_node_t mod)
21✔
3326
{
3327
   // ( port { , port } )
3328

3329
   BEGIN("list of ports");
42✔
3330

3331
   consume(tLPAREN);
21✔
3332

3333
   do {
64✔
3334
      p_port();
64✔
3335
   } while (optional(tCOMMA));
64✔
3336

3337
   consume(tRPAREN);
21✔
3338
}
21✔
3339

3340
static void p_module_nonansi_header(vlog_node_t mod)
21✔
3341
{
3342
   // { attribute_instance } module_keyword [ lifetime ] module_identifier
3343
   //    { package_import_declaration } [ parameter_port_list ] list_of_ports ;
3344

3345
   EXTEND("module non-ANSI header");
42✔
3346

3347
   p_list_of_ports(mod);
21✔
3348

3349
   consume(tSEMI);
21✔
3350

3351
   vlog_set_loc(mod, CURRENT_LOC);
21✔
3352
}
21✔
3353

3354
static vlog_node_t p_module_declaration(void)
111✔
3355
{
3356
   // module_nonansi_header [ timeunits_declaration ] { module_item }
3357
   //      endmodule [ : module_identifier ]
3358
   //   | module_ansi_header [ timeunits_declaration ] { non_port_module_item }
3359
   //      endmodule [ : module_identifier ]
3360
   //   | { attribute_instance } module_keyword [ lifetime ] module_identifier
3361
   //      ( .* ) ; [ timeunits_declaration ] { module_item } endmodule
3362
   //      [ : module_identifier ]
3363
   //   | extern module_nonansi_header
3364
   //   | extern module_ansi_header
3365

3366
   BEGIN("module declaration");
111✔
3367

3368
   vlog_node_t mod = vlog_new(V_MODULE);
111✔
3369

3370
   while (peek() == tATTRBEGIN)
111✔
UNCOV
3371
      p_attribute_instance();
×
3372

3373
   consume(tMODULE);
111✔
3374

3375
   ident_t id, ext;
111✔
3376
   p_external_identifier(&id, &ext);
111✔
3377
   vlog_set_ident2(mod, id);
111✔
3378

3379
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
111✔
3380
   vlog_set_ident(mod, qual);
111✔
3381

3382
   if (peek() == tLPAREN && peek_nth(2) == tID)
111✔
3383
      p_module_nonansi_header(mod);
21✔
3384
   else
3385
      p_module_ansi_header(mod);
90✔
3386

3387
   while (not_at_token(tENDMODULE))
618✔
3388
      p_module_item(mod);
507✔
3389

3390
   consume(tENDMODULE);
111✔
3391

3392
   return mod;
111✔
3393
}
3394

3395
static void p_udp_port_list(vlog_node_t udp)
16✔
3396
{
3397
   // output_port_identifier , input_port_identifier { , input_port_identifier }
3398

3399
   BEGIN("UDP port list");
32✔
3400

3401
   vlog_node_t oref = vlog_new(V_REF);
16✔
3402
   vlog_set_ident(oref, p_identifier());
16✔
3403
   vlog_set_loc(oref, &state.last_loc);
16✔
3404

3405
   vlog_add_port(udp, oref);
16✔
3406

3407
   consume(tCOMMA);
16✔
3408

3409
   vlog_node_t iref = vlog_new(V_REF);
16✔
3410
   vlog_set_ident(iref, p_identifier());
16✔
3411
   vlog_set_loc(iref, &state.last_loc);
16✔
3412

3413
   vlog_add_port(udp, iref);
16✔
3414

3415
   while (optional(tCOMMA)) {
38✔
3416
      vlog_node_t iref = vlog_new(V_REF);
22✔
3417
      vlog_set_ident(iref, p_identifier());
22✔
3418
      vlog_set_loc(iref, &state.last_loc);
22✔
3419

3420
      vlog_add_port(udp, iref);
22✔
3421
   }
3422
}
16✔
3423

3424
static vlog_node_t p_udp_nonansi_declaration(void)
16✔
3425
{
3426
   // { attribute_instance } primitive udp_identifier ( udp_port_list ) ;
3427

3428
   BEGIN("UDP non-ANSI declaration");
16✔
3429

3430
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
16✔
3431

3432
   consume(tPRIMITIVE);
16✔
3433

3434
   ident_t id, ext;
16✔
3435
   p_external_identifier(&id, &ext);
16✔
3436
   vlog_set_ident2(udp, id);
16✔
3437

3438
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
16✔
3439
   vlog_set_ident(udp, qual);
16✔
3440

3441
   consume(tLPAREN);
16✔
3442

3443
   p_udp_port_list(udp);
16✔
3444

3445
   consume(tRPAREN);
16✔
3446
   consume(tSEMI);
16✔
3447

3448
   vlog_set_loc(udp, CURRENT_LOC);
16✔
3449
   return udp;
16✔
3450
}
3451

3452
static void p_list_of_udp_port_identifiers(vlog_node_t udp, v_port_kind_t kind)
17✔
3453
{
3454
   // port_identifier { , port_identifier }
3455

3456
   BEGIN("list of UDP port identifiers");
34✔
3457

3458
   do {
38✔
3459
      ident_t id, ext;
38✔
3460
      p_external_identifier(&id, &ext);
38✔
3461

3462
      vlog_node_t p = vlog_new(V_PORT_DECL);
38✔
3463
      vlog_set_subkind(p, kind);
38✔
3464
      vlog_set_ident(p, id);
38✔
3465
      vlog_set_ident2(p, ext);
38✔
3466
      vlog_set_type(p, logic_type());
38✔
3467
      vlog_set_loc(p, &state.last_loc);
38✔
3468

3469
      vlog_add_decl(udp, p);
38✔
3470
   } while (optional(tCOMMA));
38✔
3471
}
17✔
3472

3473
static void p_udp_output_declaration(vlog_node_t udp, bool *has_reg)
17✔
3474
{
3475
   // { attribute_instance } output port_identifier
3476
   //    | { attribute_instance } output reg port_identifier
3477
   //         [ = constant_expression ]
3478

3479
   BEGIN("UDP output declaration");
34✔
3480

3481
   consume(tOUTPUT);
17✔
3482

3483
   const bool isreg = optional(tREG);
17✔
3484

3485
   ident_t id, ext;
17✔
3486
   p_external_identifier(&id, &ext);
17✔
3487

3488
   vlog_node_t logic = logic_type();
17✔
3489

3490
   vlog_node_t v = vlog_new(V_PORT_DECL);
17✔
3491
   vlog_set_subkind(v, V_PORT_OUTPUT);
17✔
3492
   vlog_set_ident(v, id);
17✔
3493
   vlog_set_ident2(v, ext);
17✔
3494
   vlog_set_type(v, logic);
17✔
3495
   vlog_set_loc(v, &state.last_loc);
17✔
3496

3497
   vlog_add_decl(udp, v);
17✔
3498

3499
   if (isreg) {
17✔
3500
      vlog_node_t reg = vlog_new(V_VAR_DECL);
2✔
3501
      vlog_set_loc(reg, &state.last_loc);
2✔
3502
      vlog_set_ident(reg, id);
2✔
3503
      vlog_set_type(reg, logic);
2✔
3504

3505
      vlog_add_decl(udp, reg);
2✔
3506

3507
      *has_reg = true;
2✔
3508
   }
3509
}
17✔
3510

3511
static void p_udp_input_declaration(vlog_node_t udp)
17✔
3512
{
3513
   // { attribute_instance } input list_of_udp_port_identifiers
3514

3515
   BEGIN("UDP input declaration");
34✔
3516

3517
   consume(tINPUT);
17✔
3518

3519
   p_list_of_udp_port_identifiers(udp, V_PORT_INPUT);
17✔
3520
}
17✔
3521

3522
static vlog_node_t p_udp_reg_declaration(void)
7✔
3523
{
3524
   // { attribute_instance } reg variable_identifier
3525

3526
   BEGIN("UDP reg declaration");
7✔
3527

3528
   consume(tREG);
7✔
3529

3530
   ident_t id = p_identifier();
7✔
3531

3532
   vlog_node_t reg = vlog_new(V_VAR_DECL);
7✔
3533
   vlog_set_loc(reg, &state.last_loc);
7✔
3534
   vlog_set_ident(reg, id);
7✔
3535
   vlog_set_type(reg, logic_type());
7✔
3536

3537
   return reg;
7✔
3538
}
3539

3540
static void p_udp_port_declaration(vlog_node_t udp, bool *has_reg)
39✔
3541
{
3542
   // udp_output_declaration ; | udp_input_declaration ; | udp_reg_declaration ;
3543

3544
   BEGIN("UDP port declaration");
78✔
3545

3546
   switch (peek()) {
39✔
3547
   case tOUTPUT:
16✔
3548
      p_udp_output_declaration(udp, has_reg);
16✔
3549
      break;
16✔
3550
   case tINPUT:
16✔
3551
      p_udp_input_declaration(udp);
16✔
3552
      break;
16✔
3553
   case tREG:
7✔
3554
      vlog_add_decl(udp, p_udp_reg_declaration());
7✔
3555
      *has_reg = true;
7✔
3556
      break;
7✔
UNCOV
3557
   default:
×
UNCOV
3558
      one_of(tOUTPUT, tINPUT, tREG);
×
UNCOV
3559
      break;
×
3560
   }
3561

3562
   consume(tSEMI);
39✔
3563
}
39✔
3564

3565
static void p_udp_declaration_port_list(vlog_node_t udp, bool *has_reg)
1✔
3566
{
3567
   // udp_output_declaration , udp_input_declaration { , udp_input_declaration }
3568

3569
   BEGIN("UDP declaration port list");
2✔
3570

3571
   p_udp_output_declaration(udp, has_reg);
1✔
3572

3573
   consume(tCOMMA);
1✔
3574

3575
   do {
1✔
3576
      p_udp_input_declaration(udp);
1✔
3577
   } while (optional(tCOMMA));
1✔
3578

3579
   const int ndecls = vlog_decls(udp);
1✔
3580
   for (int i = 0; i < ndecls; i++) {
4✔
3581
      vlog_node_t p = vlog_decl(udp, i);
3✔
3582
      if (vlog_kind(p) != V_PORT_DECL)
3✔
3583
         continue;
1✔
3584

3585
      vlog_node_t ref = vlog_new(V_REF);
2✔
3586
      vlog_set_loc(ref, vlog_loc(p));
2✔
3587
      vlog_set_ident(ref, vlog_ident(p));
2✔
3588
      vlog_set_ref(ref, p);
2✔
3589

3590
      vlog_add_port(udp, ref);
2✔
3591
   }
3592
}
1✔
3593

3594
static char p_output_symbol(void)
79✔
3595
{
3596
   // 0 | 1 | x | X
3597

3598
   BEGIN("output symbol");
158✔
3599

3600
   if (consume(tUDPLEVEL)) {
79✔
3601
      switch (state.last_lval.i64) {
79✔
3602
      case '0':
79✔
3603
      case '1':
3604
      case 'x':
3605
      case 'X':
3606
         return (char)state.last_lval.i64;
79✔
UNCOV
3607
      default:
×
UNCOV
3608
         parse_error(&state.last_loc, "'%c' is not a valid output symbol",
×
3609
                  (char)state.last_lval.i64);
3610
         break;
3611
      }
3612
   }
3613

3614
   return 'x';
3615
}
3616

3617
static char p_level_symbol(void)
229✔
3618
{
3619
   // 0 | 1 | x | X | ? | b | B
3620

3621
   BEGIN("level symbol");
458✔
3622

3623
   if (consume(tUDPLEVEL))
229✔
3624
      return (char)state.last_lval.i64;
229✔
3625
   else
3626
      return 'x';
3627
}
3628

3629
static char p_next_state(void)
67✔
3630
{
3631
   // output_symbol | -
3632

3633
   BEGIN("next state");
134✔
3634

3635
   switch (peek()) {
67✔
3636
   case tMINUS:
21✔
3637
      consume(tMINUS);
21✔
3638
      return '-';
21✔
3639
   case tUDPLEVEL:
46✔
3640
      return p_output_symbol();
46✔
UNCOV
3641
   default:
×
UNCOV
3642
      one_of(tUDPLEVEL, tMINUS);
×
UNCOV
3643
      return '-';
×
3644
   }
3645
}
3646

3647
static char p_edge_symbol(void)
10✔
3648
{
3649
   // r | R | f | F | p | P | n | N | *
3650

3651
   BEGIN("edge symbol");
20✔
3652

3653
   if (consume(tUDPEDGE))
10✔
3654
      return (char)state.last_lval.i64;
10✔
3655
   else
3656
      return '*';
3657
}
3658

3659
static void p_level_input_list(text_buf_t *tb)
33✔
3660
{
3661
   // level_symbol { level_symbol }
3662

3663
   BEGIN("level input list");
66✔
3664

3665
   do {
96✔
3666
      tb_append(tb, p_level_symbol());
96✔
3667
   } while (not_at_token(tCOLON));
96✔
3668
}
33✔
3669

3670
static void p_edge_indicator(text_buf_t *tb)
67✔
3671
{
3672
   // ( level_symbol level_symbol ) | edge_symbol
3673

3674
   BEGIN("edge indicator");
134✔
3675

3676
   switch (peek()) {
67✔
3677
   case tUDPEDGE:
10✔
3678
      tb_append(tb, p_edge_symbol());
10✔
3679
      break;
10✔
3680
   case tUDPIND:
57✔
3681
      consume(tUDPIND);
57✔
3682
      tb_cat(tb, state.last_lval.str);
57✔
3683
      free(state.last_lval.str);
57✔
3684
      break;
57✔
UNCOV
3685
   default:
×
3686
      should_not_reach_here();
3687
   }
3688
}
67✔
3689

3690
static void p_seq_input_list(text_buf_t *tb)
67✔
3691
{
3692
   // level_input_list | edge_input_list
3693

3694
   BEGIN("sequential input list");
134✔
3695

3696
   bool have_edge = false;
67✔
3697
   do {
133✔
3698
      switch (peek()) {
133✔
3699
      case tUDPEDGE:
67✔
3700
      case tUDPIND:
3701
         p_edge_indicator(tb);
67✔
3702
         if (have_edge)
67✔
3703
            parse_error(&state.last_loc, "a sequential input list may have at "
1✔
3704
                        "most one edge indicator");
3705
         have_edge = true;
3706
         break;
3707

3708
      case tUDPLEVEL:
66✔
3709
         tb_append(tb, p_level_symbol());
66✔
3710
         break;
66✔
3711

UNCOV
3712
      default:
×
UNCOV
3713
         one_of(tUDPEDGE, tUDPIND, tUDPLEVEL);
×
UNCOV
3714
         break;
×
3715
      }
3716
   } while (not_at_token(tCOLON));
133✔
3717
}
67✔
3718

3719
static vlog_node_t p_combinational_entry(void)
33✔
3720
{
3721
   // level_input_list : output_symbol ;
3722

3723
   BEGIN("combinational entry");
66✔
3724

3725
   LOCAL_TEXT_BUF tb = tb_new();
33✔
3726
   p_level_input_list(tb);
33✔
3727

3728
   consume(tCOLON);
33✔
3729
   tb_append(tb, ':');
33✔
3730

3731
   tb_append(tb, p_output_symbol());
33✔
3732

3733
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
33✔
3734
   vlog_set_text(v, tb_get(tb));
33✔
3735

3736
   consume(tSEMI);
33✔
3737

3738
   vlog_set_loc(v, CURRENT_LOC);
33✔
3739
   return v;
33✔
3740
}
3741

3742
static vlog_node_t p_combinational_body(void)
8✔
3743
{
3744
   // table combinational_entry { combinational_entry } endtable
3745

3746
   BEGIN("combinational UDP body");
8✔
3747

3748
   consume(tTABLE);
8✔
3749

3750
   scan_as_udp();
8✔
3751

3752
   vlog_node_t v = vlog_new(V_UDP_TABLE);
8✔
3753
   vlog_set_subkind(v, V_UDP_COMB);
8✔
3754
   vlog_set_ident(v, ident_new("combinational"));
8✔
3755

3756
   do {
33✔
3757
      vlog_add_param(v, p_combinational_entry());
33✔
3758
   } while (not_at_token(tENDTABLE));
33✔
3759

3760
   scan_as_verilog();
8✔
3761

3762
   consume(tENDTABLE);
8✔
3763

3764
   vlog_set_loc(v, CURRENT_LOC);
8✔
3765
   return v;
8✔
3766
}
3767

3768
static vlog_node_t p_sequential_entry(void)
67✔
3769
{
3770
   // seq_input_list : current_state : next_state ;
3771

3772
   BEGIN("sequential entry");
134✔
3773

3774
   LOCAL_TEXT_BUF tb = tb_new();
67✔
3775
   p_seq_input_list(tb);
67✔
3776

3777
   consume(tCOLON);
67✔
3778
   tb_append(tb, ':');
67✔
3779

3780
   tb_append(tb, p_level_symbol());
67✔
3781

3782
   consume(tCOLON);
67✔
3783
   tb_append(tb, ':');
67✔
3784

3785
   tb_append(tb, p_next_state());
67✔
3786

3787
   vlog_node_t v = vlog_new(V_UDP_ENTRY);
67✔
3788
   vlog_set_text(v, tb_get(tb));
67✔
3789

3790
   consume(tSEMI);
67✔
3791

3792
   vlog_set_loc(v, CURRENT_LOC);
67✔
3793
   return v;
67✔
3794
}
3795

3796
static vlog_node_t p_udp_initial_statement(void)
4✔
3797
{
3798
   // initial output_port_identifier = init_val ;
3799

3800
   BEGIN("UDP initial statement");
4✔
3801

3802
   consume(tINITIAL);
4✔
3803

3804
   vlog_node_t ref = vlog_new(V_REF);
4✔
3805
   vlog_set_ident(ref, p_identifier());
4✔
3806
   vlog_set_loc(ref, &state.last_loc);
4✔
3807

3808
   consume(tEQ);
4✔
3809

3810
   vlog_node_t v = vlog_new(V_BASSIGN);
4✔
3811
   vlog_set_target(v, ref);
4✔
3812
   vlog_set_value(v, p_integral_number());
4✔
3813

3814
   consume(tSEMI);
4✔
3815

3816
   vlog_set_loc(v, CURRENT_LOC);
4✔
3817
   return v;
4✔
3818
}
3819

3820
static vlog_node_t p_sequential_body(void)
9✔
3821
{
3822
   // [ udp_initial_statement ] table sequential_entry
3823
   //     { sequential_entry } endtable
3824

3825
   BEGIN("sequential UDP body");
9✔
3826

3827
   vlog_node_t v = vlog_new(V_UDP_TABLE);
9✔
3828
   vlog_set_subkind(v, V_UDP_SEQ);
9✔
3829
   vlog_set_ident(v, ident_new("sequential"));
9✔
3830

3831
   if (peek() == tINITIAL)
9✔
3832
      vlog_add_stmt(v, p_udp_initial_statement());
4✔
3833

3834
   consume(tTABLE);
9✔
3835

3836
   scan_as_udp();
9✔
3837

3838
   do {
67✔
3839
      vlog_add_param(v, p_sequential_entry());
67✔
3840
   } while (not_at_token(tENDTABLE));
67✔
3841

3842
   scan_as_verilog();
9✔
3843

3844
   consume(tENDTABLE);
9✔
3845

3846
   vlog_set_loc(v, CURRENT_LOC);
9✔
3847
   return v;
9✔
3848
}
3849

3850
static vlog_node_t p_udp_body(bool has_reg)
17✔
3851
{
3852
   // combinational_body | sequential_body
3853

3854
   BEGIN("UDP body");
34✔
3855

3856
   if (has_reg)
17✔
3857
      return p_sequential_body();
9✔
3858
   else
3859
      return p_combinational_body();
8✔
3860
}
3861

3862
static vlog_node_t p_udp_ansi_declaration(bool *has_reg)
1✔
3863
{
3864
   // { attribute_instance } primitive udp_identifier
3865
   //    ( udp_declaration_port_list ) ;
3866

3867
   BEGIN("UDP ANSI declaration");
1✔
3868

3869
   while (peek() == tATTRBEGIN)
1✔
UNCOV
3870
      p_attribute_instance();
×
3871

3872
   vlog_node_t udp = vlog_new(V_PRIMITIVE);
1✔
3873

3874
   consume(tPRIMITIVE);
1✔
3875

3876
   ident_t id, ext;
1✔
3877
   p_external_identifier(&id, &ext);
1✔
3878
   vlog_set_ident2(udp, id);
1✔
3879

3880
   ident_t qual = ident_prefix(lib_name(lib_work()), ext, '.');
1✔
3881
   vlog_set_ident(udp, qual);
1✔
3882

3883
   consume(tLPAREN);
1✔
3884

3885
   p_udp_declaration_port_list(udp, has_reg);
1✔
3886

3887
   consume(tRPAREN);
1✔
3888
   consume(tSEMI);
1✔
3889

3890
   vlog_set_loc(udp, CURRENT_LOC);
1✔
3891
   return udp;
1✔
3892
}
3893

3894
static vlog_node_t p_udp_declaration(void)
17✔
3895
{
3896
   // udp_nonansi_declaration udp_port_declaration { udp_port_declaration }
3897
   //        udp_body endprimitive [ : udp_identifier ]
3898
   //   | udp_ansi_declaration udp_body endprimitive [ : udp_identifier ]
3899
   //   | extern udp_nonansi_declaration
3900
   //   | extern udp_ansi_declaration
3901
   //   | { attribute_instance } primitive udp_identifier ( .* ) ;
3902
   //        { udp_port_declaration } udp_body endprimitive [ : udp_identifier ]
3903

3904
   BEGIN("UDP declaration");
17✔
3905

3906
   bool has_reg = false;
17✔
3907
   vlog_node_t udp;
17✔
3908
   if (peek_nth(4) == tID) {
17✔
3909
      udp = p_udp_nonansi_declaration();
16✔
3910

3911
      do {
39✔
3912
         p_udp_port_declaration(udp, &has_reg);
39✔
3913
      } while (not_at_token(tTABLE, tINITIAL));
39✔
3914
   }
3915
   else
3916
      udp = p_udp_ansi_declaration(&has_reg);
1✔
3917

3918
   vlog_add_stmt(udp, p_udp_body(has_reg));
17✔
3919

3920
   consume(tENDPRIMITIVE);
17✔
3921

3922
   return udp;
17✔
3923
}
3924

3925
static vlog_node_t p_description(void)
128✔
3926
{
3927
   // module_declaration | udp_declaration | interface_declaration
3928
   //   | program_declaration | package_declaration
3929
   //   | { attribute_instance } package_item
3930
   //   | { attribute_instance } bind_directive
3931
   //   | config_declaration
3932

3933
   BEGIN("description");
256✔
3934

3935
   switch (peek()) {
128✔
3936
   case tMODULE:
111✔
3937
      return p_module_declaration();
111✔
3938
   case tPRIMITIVE:
17✔
3939
      return p_udp_declaration();
17✔
UNCOV
3940
   default:
×
UNCOV
3941
      expect(tPRIMITIVE, tMODULE);
×
UNCOV
3942
      return NULL;
×
3943
   }
3944
}
3945

3946
static void p_timescale_compiler_directive(void)
9✔
3947
{
3948
   // `timescale time_unit / time_precision
3949

3950
   BEGIN("timescale compiler directive");
18✔
3951

3952
   consume(tTIMESCALE);
9✔
3953

3954
   consume(tUNSIGNED);
9✔
3955
   char *unit_value LOCAL = state.last_lval.str;
18✔
3956

3957
   consume(tID);
9✔
3958
   char *unit_name LOCAL = state.last_lval.str;
18✔
3959

3960
   consume(tOVER);
9✔
3961

3962
   consume(tUNSIGNED);
9✔
3963
   char *prec_value LOCAL = state.last_lval.str;
18✔
3964

3965
   consume(tID);
9✔
3966
   char *prec_name LOCAL = state.last_lval.str;
18✔
3967

3968
   set_timescale(unit_value, unit_name, prec_value, prec_name, CURRENT_LOC);
9✔
3969
}
9✔
3970

3971
static void p_defaultnettype_compiler_directive(void)
12✔
3972
{
3973
   // `default_nettype wire | tri | tri0 | tri1 | wand | triand | wor | trior | trireg | uwire | none
3974

3975
   BEGIN("default_nettype directive");
24✔
3976

3977
   consume(tDEFNETTYPE);
12✔
3978

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

3981
   // TODO: do something with the directive
3982
}
12✔
3983

3984
static void p_keywords_directive(void)
1✔
3985
{
3986
   // `begin_keywords "version_specifier"
3987

3988
   BEGIN("keywords directive");
1✔
3989

3990
   consume(tBEGINKEYWORDS);
1✔
3991

3992
   consume(tSTRING);
1✔
3993
   free(state.last_lval.str);
1✔
3994
}
1✔
3995

3996
static void p_endkeywords_directive(void)
1✔
3997
{
3998
   // `end_keywords
3999

4000
   BEGIN("endkeywords directive");
2✔
4001

4002
   consume(tENDKEYWORDS);
1✔
4003
}
1✔
4004

4005
static void p_directive_list(void)
129✔
4006
{
4007
   BEGIN("directive list");
129✔
4008

4009
   for (;;) {
152✔
4010
      switch (peek()) {
152✔
4011
      case tDEFNETTYPE:
12✔
4012
         p_defaultnettype_compiler_directive();
12✔
4013
         break;
12✔
4014
      case tTIMESCALE:
9✔
4015
         p_timescale_compiler_directive();
9✔
4016
         break;
9✔
4017
      case tBEGINKEYWORDS:
1✔
4018
         p_keywords_directive();
1✔
4019
         break;
1✔
4020
      case tENDKEYWORDS:
1✔
4021
         p_endkeywords_directive();
1✔
4022
         break;
1✔
4023
      default:
4024
         return;
129✔
4025
      }
4026
   }
4027
}
4028

4029
vlog_node_t vlog_parse(void)
224✔
4030
{
4031
   state.n_correct = RECOVER_THRESH;
224✔
4032

4033
   scan_as_verilog();
224✔
4034

4035
   if (peek() == tEOF)
224✔
4036
      return NULL;
4037

4038
   p_directive_list();
129✔
4039

4040
   make_new_arena();
129✔
4041

4042
   if (peek() == tEOF)
129✔
4043
      return NULL;
4044

4045
   return p_description();
128✔
4046
}
4047

4048
void reset_verilog_parser(void)
185✔
4049
{
4050
   state.tokenq_head = state.tokenq_tail = 0;
185✔
4051
}
185✔
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

© 2025 Coveralls, Inc