GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/parser/antlr_input.cpp Lines: 221 245 90.2 %
Date: 2021-03-23 Branches: 245 528 46.4 %

Line Exec Source
1
/*********************                                                        */
2
/*! \file antlr_input.cpp
3
 ** \verbatim
4
 ** Top contributors (to current version):
5
 **   Christopher L. Conway, Kshitij Bansal, Tim King
6
 ** This file is part of the CVC4 project.
7
 ** Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 ** in the top-level source directory and their institutional affiliations.
9
 ** All rights reserved.  See the file COPYING in the top-level source
10
 ** directory for licensing information.\endverbatim
11
 **
12
 ** \brief A super-class for ANTLR-generated input language parsers.
13
 **
14
 ** A super-class for ANTLR-generated input language parsers
15
 **/
16
17
#include "parser/antlr_input.h"
18
19
#include <antlr3.h>
20
#include <limits.h>
21
22
#include "base/check.h"
23
#include "base/output.h"
24
#include "parser/antlr_line_buffered_input.h"
25
#include "parser/bounded_token_buffer.h"
26
#include "parser/bounded_token_factory.h"
27
#include "parser/cvc/cvc_input.h"
28
#include "parser/input.h"
29
#include "parser/memory_mapped_input_buffer.h"
30
#include "parser/parser.h"
31
#include "parser/parser_exception.h"
32
#include "parser/smt2/smt2_input.h"
33
#include "parser/smt2/sygus_input.h"
34
#include "parser/tptp/tptp_input.h"
35
36
using namespace std;
37
using namespace CVC4;
38
using namespace CVC4::parser;
39
using namespace CVC4::kind;
40
41
namespace CVC4 {
42
namespace parser {
43
44
// These functions exactly wrap the antlr3 source inconsistencies.
45
// These are the only location CVC4_ANTLR3_OLD_INPUT_STREAM ifdefs appear.
46
// No other sanity checking happens;
47
pANTLR3_INPUT_STREAM newAntlr3BufferedStream(std::istream& input,
48
                                             const std::string& name,
49
                                             LineBuffer* line_buffer);
50
pANTLR3_INPUT_STREAM newAntlr3FileStream(const std::string& name);
51
pANTLR3_INPUT_STREAM newAntrl3InPlaceStream(pANTLR3_UINT8 basep,
52
                                            uint32_t size,
53
                                            const std::string& name);
54
55
pANTLR3_INPUT_STREAM newAntlr3BufferedStream(std::istream& input,
56
                                             const std::string& name,
57
                                             LineBuffer* line_buffer) {
58
  pANTLR3_INPUT_STREAM inputStream = NULL;
59
  pANTLR3_UINT8 name_duplicate = (pANTLR3_UINT8) strdup(name.c_str());
60
61
#ifdef CVC4_ANTLR3_OLD_INPUT_STREAM
62
  inputStream =
63
      antlr3LineBufferedStreamNew(input, 0, name_duplicate, line_buffer);
64
#else /* CVC4_ANTLR3_OLD_INPUT_STREAM */
65
  inputStream = antlr3LineBufferedStreamNew(input, ANTLR3_ENC_8BIT,
66
                                            name_duplicate, line_buffer);
67
#endif /* CVC4_ANTLR3_OLD_INPUT_STREAM */
68
69
  free(name_duplicate);
70
  return inputStream;
71
}
72
73
5463
pANTLR3_INPUT_STREAM newAntlr3FileStream(const std::string& name){
74
5463
  pANTLR3_INPUT_STREAM input = NULL;
75
5463
  pANTLR3_UINT8 name_duplicate = (pANTLR3_UINT8) strdup(name.c_str());
76
77
  // libantlr3c v3.2 isn't source-compatible with v3.4
78
#ifdef CVC4_ANTLR3_OLD_INPUT_STREAM
79
  input = antlr3AsciiFileStreamNew(name_duplicate);
80
#else /* CVC4_ANTLR3_OLD_INPUT_STREAM */
81
5463
  input = antlr3FileStreamNew(name_duplicate, ANTLR3_ENC_8BIT);
82
#endif /* CVC4_ANTLR3_OLD_INPUT_STREAM */
83
84
5463
  free(name_duplicate);
85
5463
  return input;
86
}
87
88
89
303
pANTLR3_INPUT_STREAM newAntrl3InPlaceStream(pANTLR3_UINT8 basep,
90
                                            uint32_t size,
91
                                            const std::string& name){
92
303
  pANTLR3_UINT8 name_duplicate = (pANTLR3_UINT8) strdup(name.c_str());
93
303
  pANTLR3_INPUT_STREAM inputStream = NULL;
94
  /* Create an ANTLR input backed by the buffer. */
95
#ifdef CVC4_ANTLR3_OLD_INPUT_STREAM
96
  inputStream =
97
    antlr3NewAsciiStringInPlaceStream(basep, size, name_duplicate);
98
#else /* CVC4_ANTLR3_OLD_INPUT_STREAM */
99
303
  inputStream =
100
    antlr3StringStreamNew(basep, ANTLR3_ENC_8BIT, size,
101
                          name_duplicate);
102
#endif /* CVC4_ANTLR3_OLD_INPUT_STREAM */
103
303
  free(name_duplicate);
104
303
  return inputStream;
105
}
106
107
5766
AntlrInputStream::AntlrInputStream(std::string name, pANTLR3_INPUT_STREAM input,
108
                                   bool fileIsTemporary,
109
                                   pANTLR3_UINT8 inputString,
110
5766
                                   LineBuffer* line_buffer)
111
    : InputStream(name, fileIsTemporary),
112
      d_input(input),
113
      d_inputString(inputString),
114
5766
      d_line_buffer(line_buffer) {
115
5766
  Assert(input != NULL);
116
5766
  input->fileName = input->strFactory->newStr8(input->strFactory, (pANTLR3_UINT8)name.c_str());
117
5766
}
118
119
17298
AntlrInputStream::~AntlrInputStream() {
120
5766
  d_input->free(d_input);
121
5766
  if(d_inputString != NULL){
122
303
    free(d_inputString);
123
  }
124
5766
  if (d_line_buffer != NULL) {
125
    delete d_line_buffer;
126
  }
127
11532
}
128
129
11532
pANTLR3_INPUT_STREAM AntlrInputStream::getAntlr3InputStream() const {
130
11532
  return d_input;
131
}
132
133
134
135
AntlrInputStream*
136
5463
AntlrInputStream::newFileInputStream(const std::string& name,
137
                                     bool useMmap)
138
{
139
#ifdef _WIN32
140
  if(useMmap) {
141
    useMmap = false;
142
  }
143
#endif
144
5463
  pANTLR3_INPUT_STREAM input = NULL;
145
5463
  if(useMmap) {
146
    input = MemoryMappedInputBufferNew(name);
147
  } else {
148
5463
    input = newAntlr3FileStream(name);
149
  }
150
5463
  if(input == NULL) {
151
    throw InputStreamException("Couldn't open file: " + name);
152
  }
153
5463
  return new AntlrInputStream(name, input, false, NULL, NULL);
154
}
155
156
157
AntlrInputStream*
158
4
AntlrInputStream::newStreamInputStream(std::istream& input,
159
                                       const std::string& name,
160
                                       bool lineBuffered)
161
{
162
4
  pANTLR3_INPUT_STREAM inputStream = NULL;
163
4
  pANTLR3_UINT8 inputStringCopy = NULL;
164
4
  LineBuffer* line_buffer = NULL;
165
166
4
  if(lineBuffered) {
167
    line_buffer = new LineBuffer(&input);
168
    inputStream = newAntlr3BufferedStream(input, name, line_buffer);
169
  } else {
170
171
    // Since these are all NULL on entry, realloc will be called
172
4
    char *basep = NULL, *boundp = NULL, *cp = NULL;
173
    /* 64KB seems like a reasonable default size. */
174
4
    size_t bufSize = 0x10000;
175
176
    /* Keep going until we can't go no more. */
177
12
    while( !input.eof() && !input.fail() ) {
178
179
4
      if( cp == boundp ) {
180
        /* We ran out of room in the buffer. Realloc at double the size. */
181
4
        ptrdiff_t offset = cp - basep;
182
4
        basep = (char *) realloc(basep, bufSize);
183
4
        if( basep == NULL ) {
184
          throw InputStreamException("Failed buffering input stream: " + name);
185
        }
186
4
        cp = basep + offset;
187
4
        boundp = basep + bufSize;
188
4
        bufSize *= 2;
189
      }
190
191
      /* Read as much as we have room for. */
192
4
      input.read( cp, boundp - cp );
193
4
      cp += input.gcount();
194
    }
195
196
    /* Make sure the fail bit didn't get set. */
197
4
    if( !input.eof() ) {
198
      throw InputStreamException("Stream input failed: " + name);
199
    }
200
4
    ptrdiff_t offset = cp - basep;
201
4
    Assert(offset >= 0);
202
4
    Assert(offset <= std::numeric_limits<uint32_t>::max());
203
4
    inputStringCopy = (pANTLR3_UINT8)basep;
204
4
    inputStream = newAntrl3InPlaceStream(inputStringCopy, (uint32_t) offset, name);
205
  }
206
207
4
  if( inputStream == NULL ) {
208
    throw InputStreamException("Couldn't initialize input: " + name);
209
  }
210
211
  return new AntlrInputStream(name, inputStream, false, inputStringCopy,
212
4
                              line_buffer);
213
}
214
215
216
AntlrInputStream*
217
299
AntlrInputStream::newStringInputStream(const std::string& input,
218
                                       const std::string& name)
219
{
220
299
  size_t input_size = input.size();
221
299
  Assert(input_size <= std::numeric_limits<uint32_t>::max());
222
223
  // Ownership of input_duplicate  is transferred to the AntlrInputStream.
224
299
  pANTLR3_UINT8 input_duplicate = (pANTLR3_UINT8) strdup(input.c_str());
225
226
299
  if( input_duplicate == NULL ) {
227
    throw InputStreamException("Couldn't initialize string input: '" + input + "'");
228
  }
229
230
299
  pANTLR3_INPUT_STREAM inputStream = newAntrl3InPlaceStream(input_duplicate, (uint32_t)input_size, name);
231
299
  if( inputStream==NULL ) {
232
    throw InputStreamException("Couldn't initialize string input: '" + input + "'");
233
  }
234
299
  return new AntlrInputStream(name, inputStream, false, input_duplicate, NULL);
235
}
236
237
5766
AntlrInput* AntlrInput::newInput(InputLanguage lang, AntlrInputStream& inputStream) {
238
  using namespace language::input;
239
240
  AntlrInput* input;
241
242
5766
  switch(lang) {
243
714
  case LANG_CVC4: {
244
714
    input = new CvcInput(inputStream);
245
714
    break;
246
  }
247
248
362
  case LANG_SYGUS_V2: input = new SygusInput(inputStream); break;
249
250
42
  case LANG_TPTP:
251
42
    input = new TptpInput(inputStream);
252
42
    break;
253
254
4648
  default:
255
4648
    if (language::isInputLang_smt2(lang))
256
    {
257
4648
      input = new Smt2Input(inputStream);
258
    }
259
    else
260
    {
261
      std::stringstream ss;
262
      ss << "unable to detect input file format, try --lang ";
263
      throw InputStreamException(ss.str());
264
    }
265
  }
266
267
5766
  return input;
268
}
269
270
5766
AntlrInput::AntlrInput(AntlrInputStream& inputStream, unsigned int lookahead) :
271
    Input(inputStream),
272
    d_lookahead(lookahead),
273
    d_lexer(NULL),
274
    d_parser(NULL),
275
5766
    d_antlr3InputStream( inputStream.getAntlr3InputStream() ),
276
11532
    d_tokenBuffer(NULL) {
277
5766
}
278
279
/*
280
AntlrParser::AntlrParser(ExprManager* exprManager, std::istream& input, const std::string& name, unsigned int lookahead)
281
  Parser(exprManager,name),
282
  d_lookahead(lookahead) {
283
284
}
285
*/
286
287
/*
288
AntlrInput::Input(ExprManager* exprManager, const std::string& input, const std::string& name, unsigned int lookahead) :
289
  Input(exprManager,name),
290
  d_lookahead(lookahead),
291
  d_lexer(NULL),
292
  d_parser(NULL),
293
  d_tokenStream(NULL) {
294
295
  char* inputStr = strdup(input.c_str());
296
  char* nameStr = strdup(name.c_str());
297
  if( inputStr==NULL || nameStr==NULL ) {
298
    throw ParserException("Couldn't initialize string input: '" + input + "'");
299
  }
300
  d_inputStream = antlr3NewAsciiStringInPlaceStream((pANTLR3_UINT8)inputStr,input.size(),(pANTLR3_UINT8)nameStr);
301
  if( d_inputStream == NULL ) {
302
    throw ParserException("Couldn't create input stream for string: '" + input + "'");
303
  }
304
305
}
306
*/
307
308
11532
AntlrInput::~AntlrInput() {
309
5766
  BoundedTokenBufferFree(d_tokenBuffer);
310
5766
}
311
312
5766
pANTLR3_COMMON_TOKEN_STREAM AntlrInput::getTokenStream() {
313
5766
  return d_tokenBuffer->commonTstream;
314
}
315
316
12
void AntlrInput::lexerError(pANTLR3_BASE_RECOGNIZER recognizer) {
317
12
  pANTLR3_LEXER lexer = (pANTLR3_LEXER)(recognizer->super);
318
12
  Assert(lexer != NULL);
319
12
  Parser *parser = (Parser*)(lexer->super);
320
12
  Assert(parser != NULL);
321
12
  AntlrInput *input = (AntlrInput*) parser->getInput();
322
12
  Assert(input != NULL);
323
324
  /* Call the error display routine *if* there's not already a
325
   * parse error pending.  If a parser error is pending, this
326
   * error is probably less important, so we just drop it. */
327
12
  if( input->d_parser->rec->state->error == ANTLR3_FALSE ) {
328
24
    input->parseError("Error finding next token.");
329
  }
330
}
331
332
144
void AntlrInput::warning(const std::string& message) {
333
144
  Warning() << getInputStream()->getName() << ':' << d_lexer->getLine(d_lexer) << '.' << d_lexer->getCharPositionInLine(d_lexer) << ": " << message << endl;
334
144
}
335
336
337
338
/**
339
 * characters considered part of a simple symbol in SMTLIB.
340
 *
341
 * TODO: Ideally this code shouldn't be smtlib specific (should work
342
 * with CVC language too), but this per-language specialization has
343
 * been left for a later point.
344
 */
345
6528
inline bool isSimpleChar(char ch) {
346
6528
  return isalnum(ch) || (strchr("~!@$%^&*_-+=<>.?/", ch) != NULL);
347
}
348
349
160
size_t wholeWordMatch(string input, string pattern, bool (*isWordChar)(char)) {
350
160
  size_t st = 0;
351
160
  size_t N = input.size();
352
1680
  while(st < N) {
353
1758
    while( st < N && (*isWordChar)(input[st])  == false ) st++;
354
820
    size_t en = st;
355
4070
    while(en + 1 < N && (*isWordChar)(input[en + 1]) == true) en++;
356
820
    if(en - st + 1 == pattern.size()) {
357
148
      bool match = true;
358
397
      for(size_t i = 0; match && i < pattern.size(); ++i) {
359
249
        match &= (pattern[i] == input[st+i]);
360
      }
361
148
      if(match == true) {
362
60
        return st;
363
      }
364
    }
365
760
    st = en + 1;
366
  }
367
100
  return string::npos;
368
}
369
370
/**
371
 * Gets part of original input and tries to visually hint where the
372
 * error might be.
373
 *
374
 * Something like:
375
 *
376
 *   ...nd (= alpha beta) (= beta delta))
377
 *                                ^
378
 *
379
 * Implementation (as on 2014/04/24):
380
 *
381
 * > if suggested pointer by lexer is under a "simple char", move to
382
 *   start of the word and print pointer there.
383
 *
384
 * > in the other case, it tries to find the nearest word in the error
385
 *   message passed along. if it can't find it, we don't add this
386
 *   visual hint, as experimentally position suggested by lexer was
387
 *   found to be totally unhelpful. (TODO: fix this upstream to
388
 *   improve)
389
 */
390
122
std::string parseErrorHelper(const char* lineStart,
391
                             std::size_t lineLength,
392
                             std::size_t charPositionInLine,
393
                             const std::string& message)
394
{
395
  // Is it a multi-line message
396
122
  bool multilineMessage = (message.find('\n') != string::npos);
397
  // Useful only if it is a multi-line message
398
122
  int firstLineEnd = message.find('\n');
399
400
244
  std::ostringstream ss, slicess;
401
402
  // Keep first line of message
403
122
  if(multilineMessage) {
404
6
    ss << message.substr(0, firstLineEnd) << endl << endl;
405
  } else {
406
116
    ss << message << endl << endl;
407
  }
408
409
122
  std::size_t posSliceStart =
410
122
      (charPositionInLine <= 50) ? 0 : charPositionInLine - 50 + 5;
411
122
  std::size_t posSliceEnd = posSliceStart + 70;
412
122
  std::size_t caretPos = 0;
413
122
  std::size_t caretPosExtra = 0;  // for inital intendation, epilipses etc.
414
415
122
  ss << "  "; caretPosExtra += 2;
416
122
  if(posSliceStart > 0) {
417
11
    ss << "..."; caretPosExtra += 3;
418
  }
419
420
2484
  for (std::size_t i = posSliceStart; i < lineLength && lineStart[i] != '\n';
421
       ++i)
422
  {
423
2366
    if(i == posSliceEnd) {
424
4
      ss << "...";
425
4
      break;
426
    }
427
2362
    if(i < charPositionInLine) { caretPos++; }
428
429
2362
    if(!isprint(lineStart[i])) {
430
      // non-printable character, something wrong, bail out
431
      return message;
432
    }
433
434
2362
    ss << (lineStart[i]);
435
2362
    slicess << (lineStart[i]);
436
  }
437
438
  // adjust position of caret, based on slice and message
439
  {
440
122
    int caretPosOrig = caretPos;
441
224
    string slice = slicess.str();
442
122
    if(isSimpleChar(slice[caretPos])) {
443
      // if alphanumeric, try to go to beginning of word/number
444
188
      while(caretPos > 0 && isSimpleChar(slice[caretPos - 1])) { --caretPos; }
445
58
      if(caretPos == 0 && posSliceStart > 0) {
446
        // reached start and this is not really the start? bail out
447
        return message;
448
      } else {
449
        // likely it is also in original message? if so, very likely
450
        // we found the right place
451
116
        string word = slice.substr(caretPos, (caretPosOrig - caretPos + 1));
452
58
        size_t matchLoc = wholeWordMatch(message, word, isSimpleChar);
453
58
        Debug("friendlyparser") << "[friendlyparser] matchLoc = " << matchLoc << endl;
454
58
        if( matchLoc != string::npos ) {
455
16
          Debug("friendlyparser") << "[friendlyparser] Feeling good." << std::endl;
456
        }
457
      }
458
    } else {
459
64
      bool foundCaretPos = false;
460
461
170
      for(int tries = 0; tries < 2 && caretPos > 0 && !foundCaretPos; ++tries) {
462
        // go to nearest alphanumeric string (before current position),
463
        // see if that word can be found in original message. If so,
464
        // point to that, else keep pointer where it was.
465
106
        int nearestWordEn = caretPos - 1;
466
236
        while(nearestWordEn > 0 && !isSimpleChar(slice[nearestWordEn])) {
467
65
          --nearestWordEn;
468
        }
469
106
        if(isSimpleChar(slice[nearestWordEn])) {
470
102
          int nearestWordSt = nearestWordEn;
471
384
          while(nearestWordSt > 0 && isSimpleChar(slice[nearestWordSt - 1])) {
472
141
            --nearestWordSt;
473
          }
474
204
          string word = slice.substr(nearestWordSt, (nearestWordEn - nearestWordSt + 1));
475
102
          size_t matchLoc = wholeWordMatch(message, word, isSimpleChar);
476
102
          Debug("friendlyparser") << "[friendlyparser] nearest word = " << word << std::endl;
477
102
          Debug("friendlyparser") << "[friendlyparser] matchLoc = " << matchLoc << endl;
478
102
          if( matchLoc != string::npos ) {
479
88
            Debug("friendlyparser") << "[friendlyparser] strong evidence that caret should be at "
480
44
                                    << nearestWordSt << std::endl;
481
44
            foundCaretPos = true;
482
          }
483
102
          caretPos = nearestWordSt;
484
        }
485
      }
486
64
      if( !foundCaretPos) {
487
        // this doesn't look good. caret generally getting printed
488
        // at unhelpful positions. improve upstream?
489
20
        return message;
490
      }
491
    }
492
102
    caretPos += caretPosExtra;
493
  }// end of caret position computation/heuristics
494
495
102
  ss << std::endl;
496
2680
  while( caretPos-- > 0 ) {
497
1289
    ss << ' ';
498
  }
499
102
  ss << '^' << endl;
500
102
  if(multilineMessage) {
501
6
     ss << message.substr(firstLineEnd, message.size() - firstLineEnd);;
502
  }
503
102
  return ss.str();
504
}
505
506
122
void AntlrInput::parseError(const std::string& message, bool eofException)
507
{
508
244
  auto lineLength = d_antlr3InputStream->sizeBuf
509
122
                    - (static_cast<char*>(d_antlr3InputStream->currentLine)
510
122
                       - static_cast<char*>(d_antlr3InputStream->data));
511
  std::string updatedMessage = parseErrorHelper(
512
122
      (const char*)d_antlr3InputStream->getLineBuf(d_antlr3InputStream),
513
      lineLength,
514
122
      d_lexer->getCharPositionInLine(d_lexer),
515
366
      message);
516
517
244
  Debug("parser") << "Throwing exception: "
518
244
      << (const char*)d_lexer->rec->state->tokSource->fileName->chars << ":"
519
244
      << d_lexer->getLine(d_lexer) << "."
520
244
      << d_lexer->getCharPositionInLine(d_lexer) << ": "
521
122
      << updatedMessage << endl;
522
122
  if(eofException) {
523
    throw ParserEndOfFileException(message,
524
6
                                   (const char*)d_lexer->rec->state->tokSource->fileName->chars,
525
6
                                   d_lexer->getLine(d_lexer),
526
18
                                   d_lexer->getCharPositionInLine(d_lexer));
527
  } else {
528
    throw ParserException(updatedMessage,
529
116
                          (const char*)d_lexer->rec->state->tokSource->fileName->chars,
530
116
                          d_lexer->getLine(d_lexer),
531
348
                          d_lexer->getCharPositionInLine(d_lexer));
532
  }
533
}
534
535
536
5766
void AntlrInput::setAntlr3Lexer(pANTLR3_LEXER pLexer) {
537
5766
  d_lexer = pLexer;
538
539
5766
  pANTLR3_TOKEN_FACTORY pTokenFactory = d_lexer->rec->state->tokFactory;
540
5766
  if( pTokenFactory != NULL ) {
541
5766
    pTokenFactory->close(pTokenFactory);
542
  }
543
544
  /* 2*lookahead should be sufficient, but we give ourselves some breathing room. */
545
5766
  pTokenFactory = BoundedTokenFactoryNew(d_antlr3InputStream, 2*d_lookahead);
546
5766
  if( pTokenFactory == NULL ) {
547
    throw InputStreamException("Couldn't create token factory.");
548
  }
549
5766
  d_lexer->rec->state->tokFactory = pTokenFactory;
550
551
5766
  pBOUNDED_TOKEN_BUFFER buffer = BoundedTokenBufferSourceNew(d_lookahead, d_lexer->rec->state->tokSource);
552
5766
  if( buffer == NULL ) {
553
    throw InputStreamException("Couldn't create token buffer.");
554
  }
555
556
5766
  d_tokenBuffer = buffer;
557
558
  // Override default lexer error reporting
559
5766
  d_lexer->rec->reportError = &lexerError;
560
  // Override default nextToken function, just to prevent exceptions escaping.
561
5766
  d_lexer->rec->state->tokSource->nextToken = &nextToken;
562
5766
}
563
564
5766
void AntlrInput::setParser(Parser& parser) {
565
  // ANTLR isn't using super in the lexer or the parser, AFAICT.
566
  // We could also use @lexer/parser::context to add a field to the generated
567
  // objects, but then it would have to be declared separately in every
568
  // language's grammar and we'd have to in the address of the field anyway.
569
5766
  d_lexer->super = &parser;
570
5766
  d_parser->super = &parser;
571
5766
}
572
573
5766
void AntlrInput::setAntlr3Parser(pANTLR3_PARSER pParser) {
574
5766
  d_parser = pParser;
575
//  d_parser->rec->match = &match;
576
5766
  d_parser->rec->reportError = &reportError;
577
  /* Don't try to recover from a parse error. */
578
  // [chris 4/5/2010] Not clear on why this cast is necessary, but I get an error if I remove it.
579
11532
  d_parser->rec->recoverFromMismatchedToken =
580
      (void* (*)(ANTLR3_BASE_RECOGNIZER_struct*, ANTLR3_UINT32, ANTLR3_BITSET_LIST_struct*))
581
11532
      d_parser->rec->mismatch;
582
5766
}
583
584
}/* CVC4::parser namespace */
585
26673
}/* CVC4 namespace */