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

nickg / nvc / 13174766953

06 Feb 2025 08:30AM UTC coverage: 92.162% (+0.002%) from 92.16%
13174766953

push

github

nickg
Include type name in range_of backtrace message. Issue xxx

64133 of 69587 relevant lines covered (92.16%)

498167.34 hits per line

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

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

18
#include "util.h"
19
#include "array.h"
20
#include "diag.h"
21
#include "ident.h"
22
#include "option.h"
23
#include "scan.h"
24
#include "hash.h"
25

26
#include <assert.h>
27
#include <fcntl.h>
28
#include <unistd.h>
29
#include <string.h>
30
#include <stdarg.h>
31
#include <stdlib.h>
32

33
typedef struct {
34
   bool  result;
35
   bool  taken;
36
   loc_t loc;
37
} cond_state_t;
38

39
typedef A(cond_state_t) cond_stack_t;
40

41
typedef struct {
42
   ident_t name;
43
   loc_t   expandloc;
44
} macro_expansion_t;
45

46
typedef A(macro_expansion_t) macro_stack_t;
47

48
static const char    *file_start;
49
static size_t         file_sz;
50
static const char    *read_ptr;
51
static hdl_kind_t     src_kind;
52
static file_ref_t     file_ref = FILE_INVALID;
53
static int            colno;
54
static int            lineno;
55
static int            lookahead;
56
static int            pperrors;
57
static cond_stack_t   cond_stack;
58
static shash_t       *pp_defines;
59
static macro_stack_t  macro_stack;
60

61
extern int yylex(void);
62

63
extern void reset_scanner(void);
64

65
static bool pp_cond_analysis_expr(void);
66
static void pp_defines_init();
67

68
yylval_t yylval;
69
loc_t yylloc;
70

71
void input_from_buffer(const char *buf, size_t len, hdl_kind_t kind)
4,461✔
72
{
73
   pp_defines_init();
4,461✔
74

75
   reset_scanner();
4,461✔
76

77
   yylloc = LOC_INVALID;
4,461✔
78

79
   file_start = buf;
4,461✔
80
   file_sz    = len;
4,461✔
81
   src_kind   = kind;
4,461✔
82
   read_ptr   = buf;
4,461✔
83
   lineno     = 1;
4,461✔
84
   colno      = 0;
4,461✔
85
   lookahead  = -1;
4,461✔
86
   pperrors   = 0;
4,461✔
87

88
   switch (kind) {
4,461✔
89
   case SOURCE_VERILOG:
184✔
90
      reset_verilog_parser();
184✔
91
      break;
184✔
92
   case SOURCE_VHDL:
4,253✔
93
      reset_vhdl_parser();
4,253✔
94
      break;
4,253✔
95
   case SOURCE_SDF:
24✔
96
      reset_sdf_parser();
24✔
97
      break;
24✔
98
   }
99
}
4,461✔
100

101
void input_from_file(const char *file)
4,381✔
102
{
103
   // TODO: need a more sophisticated mechanism to determine HDL type
104
   hdl_kind_t kind = SOURCE_VHDL;
4,381✔
105
   size_t len = strlen(file);
4,381✔
106
   if (len > 2 && file[len - 2] == '.' && file[len - 1] == 'v')
4,381✔
107
      kind = SOURCE_VERILOG;
108
   else if (len > 3 && strcmp(file + len - 3, ".sv") == 0)
4,277✔
109
      kind = SOURCE_VERILOG;
110
   else if (len > 4 && !strcmp(&(file[len - 4]), ".sdf")) {
4,277✔
111
      kind = SOURCE_SDF;
24✔
112
   }
113

114
   int fd;
4,381✔
115
   if (strcmp(file, "-") == 0)
4,381✔
116
      fd = STDIN_FILENO;
117
   else {
118
      fd = open(file, O_RDONLY);
4,340✔
119
      if (fd < 0)
4,340✔
120
         fatal_errno("opening %s", file);
×
121
   }
122

123
   file_info_t info;
4,381✔
124
   if (!get_handle_info(fd, &info))
4,381✔
125
      fatal_errno("%s: cannot get file info", file);
×
126

127
   if (info.type == FILE_FIFO) {
4,381✔
128
      // Read all the data from the pipe into a buffer
129
      size_t bufsz = 16384, total = 0;
38✔
130
      char *buf = xmalloc(bufsz);
38✔
131
      int nbytes;
76✔
132
      do {
76✔
133
         if (bufsz - 1 - file_sz == 0)
76✔
134
            buf = xrealloc(buf, bufsz *= 2);
×
135

136
         nbytes = read(fd, buf + total, bufsz - 1 - total);
76✔
137
         if (nbytes < 0)
76✔
138
            fatal_errno("read");
×
139

140
         total += nbytes;
76✔
141
         buf[total] = '\0';
76✔
142
      } while (nbytes > 0);
76✔
143

144
      input_from_buffer(buf, total, kind);
38✔
145
   }
146
   else if (info.type == FILE_REGULAR) {
4,343✔
147
      void *map = NULL;
4,343✔
148
      if (info.size > 0)
4,343✔
149
         map = map_file(fd, info.size);
4,342✔
150

151
      file_ref = loc_file_ref(file, map);
4,343✔
152

153
      input_from_buffer(map, info.size, kind);
4,343✔
154
   }
155
   else
156
      fatal("opening %s: not a regular file", file);
×
157

158
   close(fd);
4,381✔
159
}
4,381✔
160

161
hdl_kind_t source_kind(void)
3,552✔
162
{
163
   return src_kind;
3,552✔
164
}
165

166
int get_next_char(char *b, int max_buffer)
9,757✔
167
{
168
   const ptrdiff_t navail = (file_start - read_ptr) + file_sz;
9,757✔
169
   assert(navail >= 0);
9,757✔
170

171
   if (navail == 0)
9,757✔
172
      return 0;
173

174
   const int nchars = MIN(navail, max_buffer);
5,288✔
175

176
   memcpy(b, read_ptr, nchars);
5,288✔
177
   read_ptr += nchars;
5,288✔
178

179
   return nchars;
5,288✔
180
}
181

182
void begin_token(char *tok, int length)
3,316,373✔
183
{
184
   // Newline must match as a single token for the logic below to work
185
   assert(strchr(tok, '\n') == NULL || length == 1);
3,316,373✔
186

187
   if (macro_stack.count == 0) {
3,316,373✔
188
      const int first_col = colno;
3,316,277✔
189
      if (*tok == '\n') {
3,316,277✔
190
         colno = 0;
385,850✔
191
         lineno += 1;
385,850✔
192
      }
193
      else
194
         colno += length;
2,930,427✔
195

196
      const int last_col = first_col + length - 1;
3,316,277✔
197

198
      extern loc_t yylloc;
3,316,277✔
199
      yylloc = get_loc(lineno, first_col, lineno, last_col, file_ref);
3,316,277✔
200
   }
201
   else
202
      yylloc = macro_stack.items[0].expandloc;
96✔
203
}
3,316,373✔
204

205
const char *token_str(token_t tok)
191✔
206
{
207
   if (tok == tEOF)
191✔
208
      return "end of file";
209
   else if (tok < 128) {
189✔
210
      static char buf[2];
43✔
211
      buf[0] = tok;
43✔
212
      return buf;
43✔
213
   }
214
   else {
215
      static const char *token_strs[] = {
146✔
216
         "identifier", "entity", "is", "end", "generic", "port", "constant",
217
         "component", "configuration", "architecture", "of", "begin", "for",
218
         "type", "to", "all", "in", "out", "buffer", "bus", "unaffected",
219
         "signal", "downto", "process", "postponed", "wait", "report", ":=",
220
         "integer", "string", "error", "inout", "linkage", "variable", "if",
221
         "range", "subtype", "units", "package", "library", "use", "null",
222
         "function", "impure", "return", "pure", "array", "<>", "=>", "others",
223
         "assert", "severity", "on", "map", "then", "else", "elsif", "body",
224
         "while", "loop", "after", "alias", "attribute", "procedure", "exit",
225
         "next", "when", "case", "label", "group", "literal", "inertial",
226
         "transport", "reject", "bit string", "block", "with", "select",
227
         "generate", "access", "file", "open", "real", "until", "record",
228
         "new", "shared", "and", "or", "nand", "nor", "xor", "xnor", "/=",
229
         "<=", ">=", "**", "sll", "srl", "sla", "sra", "rol", "ror", "mod",
230
         "rem", "abs", "not", "guarded", "reverse_range", "protected",
231
         "context", "`if", "`else", "`elsif", "`end", "`error", "`warning",
232
         "translate_off", "translate_on", "?=", "?/=", "?<", "?<=", "?>",
233
         "?>=", "register", "disconnect", "??", "<<", ">>", "force", "release",
234
         "parameter", "coverage on", "coverage off", "PSL directive", "always",
235
         "->", "<->", "default", "clock", "next!", "never", "eventually!",
236
         "next_a", "next_a!", "next_e", "next_e!", "next_event", "next_event!",
237
         "module", "endmodule", "input", "output", "reg", "posedge", "negedge",
238
         "initial", "wire", "unsigned", "assume", "assume_guarantee",
239
         "restrict", "restrict_guarantee", "strong", "fairness", "cover",
240
         "property", "sequence", "const", "mutable", "hdltype", "boolean",
241
         "bit", "bitvector", "numeric", "string", "[*", "[+]", "[->", "[=",
242
         "&&", "within", "system task", "view", "private", "prev", "stable",
243
         "rose", "fell", "ended", "nondet", "nondetv", "union", "translate on",
244
         "translate off", "until!", "until_", "until!_", "`timescale",
245
         "supply0", "supply1", "pulldown", "pullup", "===", "!==", "==", "!=",
246
         "(*", "*)", "number", "forever", "[[", "]]", "specify", "endspecify",
247
         "primitive", "endprimitive", "table", "endtable", "assign",
248
         "level symbol", "edge symbol", "edge indicator", "buf", "||",
249
         "scalar constant (0)", "scalar constant (1)", "delay file",
250
         "sdf version", "design", "date", "vendor", "program", "version",
251
         "divider", "voltage", "temperature", "cell", "celltype", "instance",
252
         "delay", "timing check", "timing env", "path pulse",
253
         "path pulse percent", "IO path", "retain", "cond", "condelse",
254
         "interconnect", "net delay", "device", "setup", "hold", "setuphold",
255
         "recovery", "removal", "recrem", "skew", "bidirectional skew", "width",
256
         "period", "nochange", "cond", "scond", "ccond", "path constraint",
257
         "period constraint", "sum", "diff", "skew constraint", "exception",
258
         "name", "arrival", "departure", "slack", "waveform", "increment",
259
         "absolute", "~&", "~|", "~^", "struct", "packed", "void", "byte",
260
         "shortint", "longint", "int", "integer", "time", "typedef", "logic",
261
         "enum", "tagged", "abort", "sync_abort", "async_abort", "before",
262
         "before!", "before_", "before!_", "|->", "|=>", "next", "inf",
263
         "repeat", "do", "endpoint", "<<", ">>", "<<<", ">>>", "task",
264
         "endtask", "endfunction", "`begin_keywords", "`end_keywords", "real",
265
         "shortreal", "realtime", "`__nvc_push", "`__nvc_pop", "++", "--",
266
         "var", "`default_nettype", "tri", "tri0", "tri1", "wand", "triand",
267
         "wor", "trior", "trireg", "uwire", "none",
268
      };
269

270
      if (tok >= 200 && tok - 200 < ARRAY_LEN(token_strs))
146✔
271
         return token_strs[tok - 200];
146✔
272
   }
273

274
   return "???";
275
}
276

277
void free_token(token_t tok, yylval_t *lval)
1,593✔
278
{
279
   if (tok == tSTRING || tok == tBITSTRING)
1,593✔
280
      free(lval->str);
8✔
281

282
   DEBUG_ONLY(lval->str = NULL);
1,593✔
283
}
1,593✔
284

285
static void pp_defines_init(void)
30,646✔
286
{
287
   if (pp_defines != NULL)
30,646✔
288
      return;
289

290
   pp_defines = shash_new(16);
4,344✔
291

292
   pp_defines_add("VHDL_VERSION", standard_text(standard()));
4,344✔
293
   pp_defines_add("TOOL_TYPE",    "SIMULATION");
4,344✔
294
   pp_defines_add("TOOL_VENDOR",  PACKAGE_URL);
4,344✔
295
   pp_defines_add("TOOL_NAME",    PACKAGE_NAME);
4,344✔
296
   pp_defines_add("TOOL_EDITION", "GPL");
4,344✔
297
   pp_defines_add("TOOL_VERSION", PACKAGE_VERSION);
4,344✔
298
}
299

300
void pp_defines_add(const char *name, const char *value)
26,079✔
301
{
302
   pp_defines_init();
26,079✔
303

304
   bool valid = isalpha_iso88591(name[0]) || name[0] == '_';
26,079✔
305
   for (const char *p = name + 1; valid && *p; p++)
282,444✔
306
      valid &= isalnum_iso88591(*p) || *p == '_';
256,365✔
307

308
   if (!valid)
26,079✔
309
      errorf("\"%s\" is not a valid conditional analysis identifier", name);
×
310

311
   char *existing_val = shash_get(pp_defines, name);
26,079✔
312
   if (existing_val) {
26,079✔
313
      warnf("conditional analysis identifier '%s' already defined (%s)",
×
314
            name, existing_val);
315
      free(existing_val);
×
316
   }
317

318
   shash_put(pp_defines, name, xstrdup(value));
26,079✔
319
}
26,079✔
320

321
const char *pp_defines_get(const char *name)
24✔
322
{
323
   pp_defines_init();
24✔
324
   return shash_get(pp_defines, name);
24✔
325
}
326

327
void pp_defines_iter(pp_iter_t fn, void *ctx)
82✔
328
{
329
   pp_defines_init();
82✔
330

331
   const char *key;
82✔
332
   void *value;
82✔
333
   for (hash_iter_t it = HASH_BEGIN;
82✔
334
        shash_iter(pp_defines, &it, &key, &value); )
586✔
335
      (*fn)(key, value, ctx);
504✔
336
}
82✔
337

338
static int pp_yylex(void)
1,708,112✔
339
{
340
   const int tok = lookahead != -1 ? lookahead : yylex();
1,708,112✔
341
   lookahead = -1;
1,708,112✔
342
   return tok;
1,708,112✔
343
}
344

345
static void pp_error(const char *fmt, ...)
3✔
346
{
347
   va_list ap;
3✔
348
   va_start(ap, fmt);
3✔
349

350
   if (pperrors++ == 0 || opt_get_int(OPT_UNIT_TEST)) {
3✔
351
      diag_t *d = diag_new(DIAG_ERROR, &yylloc);
3✔
352
      diag_vprintf(d, fmt, ap);
3✔
353
      diag_emit(d);
3✔
354
   }
355

356
   va_end(ap);
3✔
357
}
3✔
358

359
static bool pp_expect(int expect)
129✔
360
{
361
   const int got = pp_yylex();
129✔
362
   if (got != expect) {
129✔
363
      pp_error("expected $yellow$%s$$ while parsing conditional "
×
364
               "directive but found $yellow$%s$$", token_str(expect),
365
               token_str(got));
366
      return false;
×
367
   }
368

369
   return true;
370
}
371

372
static bool pp_cond_analysis_relation(void)
60✔
373
{
374
   // ( conditional_analysis_expression )
375
   //   | not ( conditional_analysis_expression )
376
   //   | conditional_analysis_identifier = string_literal
377
   //   | conditional_analysis_identifier /= string_literal
378
   //   | conditional_analysis_identifier < string_literal
379
   //   | conditional_analysis_identifier <= string_literal
380
   //   | conditional_analysis_identifier > string_literal
381
   //   | conditional_analysis_identifier >= string_literal
382

383
   bool result = false;
60✔
384
   token_t tok = pp_yylex();
60✔
385

386
   switch (tok) {
60✔
387
   case tLPAREN:
×
388
      result = pp_cond_analysis_expr();
×
389
      pp_expect(tRPAREN);
×
390
      break;
×
391

392
   case tNOT:
1✔
393
      pp_expect(tLPAREN);
1✔
394
      result = !pp_cond_analysis_expr();
1✔
395
      pp_expect(tRPAREN);
1✔
396
      break;
1✔
397

398
   case tID:
59✔
399
      {
400
         const char *name = istr(yylval.ident);
59✔
401
         token_t rel = pp_yylex();
59✔
402

403
         if (pp_expect(tSTRING)) {
59✔
404
            const char *value = shash_get(pp_defines, name);
59✔
405
            if (value == NULL)
59✔
406
               pp_error("undefined conditional analysis identifier %s", name);
1✔
407
            else {
408
               char *cmp = yylval.str + 1;
58✔
409
               cmp[strlen(cmp) - 1] = '\0';
58✔
410

411
               switch (rel) {
58✔
412
               case tEQ:
17✔
413
                  result = strcmp(value, cmp) == 0;
17✔
414
                  break;
17✔
415
               case tNEQ:
1✔
416
                  result = strcmp(value, cmp) != 0;
1✔
417
                  break;
1✔
418
               case tLT:
39✔
419
                  result = strcmp(value, cmp) < 0;
39✔
420
                  break;
39✔
421
               case tLE:
×
422
                  result = strcmp(value, cmp) <= 0;
×
423
                  break;
×
424
               case tGT:
×
425
                  result = strcmp(value, cmp) > 0;
×
426
                  break;
×
427
               case tGE:
1✔
428
                  result = strcmp(value, cmp) >= 0;
1✔
429
                  break;
1✔
430
               default:
×
431
                  pp_error("expected conditional analysis relation "
×
432
                           "but found $yellow$%s$$", token_str(rel));
433
                  break;
×
434
               }
435
            }
436

437
            free(yylval.str);
59✔
438
         }
439
      }
440
      break;
441

442
   default:
×
443
      pp_error("unexpected $yellow$%s$$ while parsing conditional "
×
444
               "analysis relation", token_str(tok));
445
   }
446

447
   return result;
60✔
448
}
449

450
static bool pp_cond_analysis_expr(void)
59✔
451
{
452
   // conditional_analysis_relation
453
   //   | conditional_analysis_relation { and conditional_analysis_relation }
454
   //   | conditional_analysis_relation { or conditional_analysis_relation }
455
   //   | conditional_analysis_relation { xor conditional_analysis_relation }
456
   //   | conditional_analysis_relation { xnor conditional_analysis_relation }
457

458
   const bool lhs = pp_cond_analysis_relation();
59✔
459
   switch ((lookahead = pp_yylex())) {
59✔
460
   case tAND:
1✔
461
      lookahead = -1;
1✔
462
      return pp_cond_analysis_relation() && lhs;
1✔
463
   case tOR:
×
464
      lookahead = -1;
×
465
      return pp_cond_analysis_relation() || lhs;
×
466
   case tXOR:
×
467
      lookahead = -1;
×
468
      return pp_cond_analysis_relation() ^ lhs;
×
469
   case tXNOR:
×
470
      lookahead = -1;
×
471
      return !(pp_cond_analysis_relation() ^ lhs);
×
472
   default:
473
      return lhs;
474
   }
475
   return lhs;
476
}
477

478
static void macro_hint_cb(diag_t *d, void *ctx)
1✔
479
{
480
   assert(macro_stack.count > 0);
1✔
481

482
   for (int i = 0; i < macro_stack.count; i++)
3✔
483
      diag_hint(d, NULL, "while expanding macro %s",
2✔
484
                istr(macro_stack.items[i].name));
2✔
485
}
1✔
486

487
static void pp_nvc_push(void)
11✔
488
{
489
   token_t tok;
11✔
490
   macro_expansion_t exp = {};
11✔
491
   unsigned first_line, first_column, column_delta;
11✔
492

493
   if ((tok = pp_yylex()) != tID)
11✔
494
      goto error;
×
495

496
   exp.name = ident_new(yylval.str);
11✔
497
   free(yylval.str);
11✔
498

499
   if ((tok = pp_yylex()) != tCOMMA)
11✔
500
      goto error;
×
501

502
   if ((tok = pp_yylex()) != tUNSIGNED)
11✔
503
      goto error;
×
504

505
   first_line = atoi(yylval.str);
11✔
506
   free(yylval.str);
11✔
507

508
   if ((tok = pp_yylex()) != tCOLON)
11✔
509
      goto error;
×
510

511
   if ((tok = pp_yylex()) != tUNSIGNED)
11✔
512
      goto error;
×
513

514
   first_column = atoi(yylval.str);
11✔
515
   free(yylval.str);
11✔
516

517
   if ((tok = pp_yylex()) != tCOMMA)
11✔
518
      goto error;
×
519

520
   if ((tok = pp_yylex()) != tUNSIGNED)
11✔
521
      goto error;
×
522

523
   column_delta = atoi(yylval.str);
11✔
524
   free(yylval.str);
11✔
525

526
   exp.expandloc = get_loc(first_line, first_column, first_line,
11✔
527
                           first_column + column_delta, yylloc.file_ref);
11✔
528

529
   if (macro_stack.count == 0)
11✔
530
      diag_add_hint_fn(macro_hint_cb, NULL);
7✔
531

532
   APUSH(macro_stack, exp);
11✔
533
   return;
11✔
534

535
 error:
×
536
   pp_error("unexpected %s while parsing `__nvc_push directive",
×
537
            token_str(tok));
538
}
539

540
static void pp_nvc_pop(void)
11✔
541
{
542
   if (macro_stack.count == 0)
11✔
543
      return;
544

545
   const macro_expansion_t top = APOP(macro_stack);
11✔
546
   lineno = top.expandloc.first_line - 1;
11✔
547
   colno = top.expandloc.first_column + top.expandloc.column_delta;
11✔
548

549
   if (macro_stack.count == 0)
11✔
550
      diag_remove_hint_fn(macro_hint_cb);
7✔
551
}
552

553
token_t processed_yylex(void)
1,706,059✔
554
{
555
   assert(lookahead == -1);
1,706,059✔
556

557
   for (;;) {
1,707,728✔
558
      token_t token = pp_yylex();
1,707,728✔
559
      switch (token) {
1,707,728✔
560
      case tCONDIF:
54✔
561
         {
562
            cond_state_t new = { .loc = yylloc };
54✔
563
            new.result = new.taken = pp_cond_analysis_expr();
54✔
564

565
            if (cond_stack.count > 0 && !ATOP(cond_stack).result) {
54✔
566
               // Suppress nested conditionals in not-taken branches
567
               new.taken = true;
1✔
568
               new.result = false;
1✔
569
            }
570

571
            pp_expect(tTHEN);
54✔
572

573
            new.loc.column_delta =
54✔
574
               yylloc.first_column + yylloc.column_delta - new.loc.first_column;
54✔
575
            new.loc.line_delta =
54✔
576
               yylloc.first_line + yylloc.line_delta - new.loc.first_line;
54✔
577

578
            APUSH(cond_stack, new);
54✔
579
         }
580
         break;
54✔
581

582
      case tCONDELSIF:
4✔
583
         {
584
            if (cond_stack.count == 0)
4✔
585
               pp_error("unexpected $yellow$%s$$ outside conditional "
1✔
586
                        "analysis block", token_str(token));
587

588
            const bool result = pp_cond_analysis_expr();
4✔
589

590
            if (cond_stack.count > 0) {
4✔
591
               if (!ATOP(cond_stack).taken) {
3✔
592
                  ATOP(cond_stack).result = result;
2✔
593
                  ATOP(cond_stack).taken = result;
2✔
594
               }
595
               else
596
                  ATOP(cond_stack).result = false;
1✔
597
            }
598

599
            pp_expect(tTHEN);
4✔
600
         }
601
         break;
4✔
602

603
      case tCONDELSE:
12✔
604
         {
605
            if (cond_stack.count == 0)
12✔
606
               pp_error("unexpected $yellow$%s$$ outside conditional "
×
607
                        "analysis block", token_str(token));
608
            else {
609
               cond_state_t *cs = &(cond_stack.items[cond_stack.count - 1]);
12✔
610
               cs->result = !(cs->taken);
12✔
611
            }
612
         }
613
         break;
614

615
      case tCONDEND:
54✔
616
         {
617
            if (cond_stack.count == 0)
54✔
618
               pp_error("unexpected $yellow$%s$$ outside conditional "
1✔
619
                        "analysis block", token_str(token));
620
            else
621
               APOP(cond_stack);
53✔
622

623
            if ((lookahead = yylex()) == tIF)
54✔
624
               lookahead = -1;
46✔
625
         }
626
         break;
627

628
      case tCONDERROR:
10✔
629
      case tCONDWARN:
630
         {
631
            loc_t loc = yylloc;
10✔
632
            if (pp_expect(tSTRING)) {
10✔
633
               loc.column_delta =
10✔
634
                  yylloc.first_column + yylloc.column_delta - loc.first_column;
10✔
635
               loc.line_delta =
10✔
636
                  yylloc.first_line + yylloc.line_delta - loc.first_line;
10✔
637

638
               if (cond_stack.count == 0 || ATOP(cond_stack).result) {
10✔
639
                  const diag_level_t level =
10✔
640
                     token == tCONDWARN ? DIAG_WARN : DIAG_ERROR;
5✔
641
                  diag_t *d = diag_new(level, &loc);
5✔
642
                  diag_printf(d, "%s", yylval.str);
5✔
643
                  diag_emit(d);
5✔
644
               }
645

646
               free(yylval.str);
10✔
647
            }
648
         }
649
         break;
10✔
650

651
      case tEOF:
652
         while (cond_stack.count > 0) {
4,382✔
653
            error_at(&(ATOP(cond_stack).loc), "unterminated conditional "
1✔
654
                     "analysis block");
655
            APOP(cond_stack);
1✔
656
         }
657
         return tEOF;
658

659
      case tNVCPUSH:
11✔
660
         pp_nvc_push();
11✔
661
         break;
11✔
662

663
      case tNVCPOP:
11✔
664
         pp_nvc_pop();
11✔
665
         break;
11✔
666

667
      default:
1,703,191✔
668
         if (cond_stack.count == 0 || ATOP(cond_stack).result)
1,703,191✔
669
            return token;
1,701,678✔
670
         else {
671
            free_token(token, &yylval);
1,513✔
672
            break;
1,513✔
673
         }
674
      }
675
   }
676
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc