Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
/**************************************************************************/
/* */
/* This file is part of Frama-Clang */
/* */
/* Copyright (C) 2012-2018 */
/* CEA (Commissariat à l'énergie atomique et aux énergies */
/* alternatives) */
/* */
/* you can redistribute it and/or modify it under the terms of the GNU */
/* Lesser General Public License as published by the Free Software */
/* Foundation, version 2.1. */
/* */
/* It is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU Lesser General Public License for more details. */
/* */
/* See the GNU Lesser General Public License version 2.1 */
/* for more details (enclosed in the file LICENSE). */
/* */
/**************************************************************************/
//
// Description:
// Definition of the ACSL++ parser.
//
#ifndef ACSL_ParserH
#define ACSL_ParserH
#include "ACSLLexer.h"
#include "Clang_utils.h"
#include "clang/AST/DeclCXX.h"
#include <initializer_list>
/** @file */
namespace clang {
class ASTContext;
class DeclContext;
class Sema;
class Scope;
class MacroArgs;
class Token;
class MacroInfo;
} // end of namespace clang
class RTTITable;
namespace Acsl {
/*! @class ErrorMessage
* @brief Represents an error message in the parser.
*
* The parser Parser can stop parsing at the first error message or it can
* try to recover a <em>natural state</em> after an error is reported. In
* the last case many ErrorMessage are stored in the Parser::_errorMessages
* field.
*/
class ErrorMessage {
private:
std::string _message; //!< Content of the error message.
std::string _filePos; //!< File name in which the error occurs.
unsigned _linePos; //!< Line at which the error occurs.
unsigned _columnPos; //!< Column at which the error occurs.
public:
ErrorMessage(const std::string& message, const std::string& filePos,
unsigned linePos, unsigned columnPos)
: _message(message), _filePos(filePos), _linePos(linePos),
_columnPos(columnPos) {}
const std::string& getMessage() const { return _message; }
const std::string& filepos() const { return _filePos; }
unsigned linepos() const { return _linePos; }
unsigned columnpos() const { return _columnPos; }
};
/*! @class Parser
* @brief Builds a logical CIL AST from Token read by the intern Lexer
* _arguments._lexer.
*
* The parser Parser can stop parsing at the first error message or it can
* try to recover a <em>natural state</em> after an error is reported. In
* the last case many ErrorMessage are stored in the
* Parser::Arguments::_errorMessages field. \n
* The main method is the parse method. Assumed that an initial state is
* provided to the constructor Parser::Parser, the parse method makes it
* evolve. Each time a transition is taken, a reference to a node of the CIL
* AST stored within the state enables to build another piece of the AST.
*/
class Parser : public ::Parser::Base {
public:
/*! @class Arguments
* @brief Provides accessibility to some high-level constructs during
* the parsing. The selected services helps to construct local nodes in
* the CIL AST.
*/
class Arguments {
private:
//! @name Parsing information data members
///@{
Lexer _lexer; //!< lexer used to provide Token to the grammar.
location _tokenLocation;
//!< location of the current token _lexer.queryToken().
clang::SourceLocation _clangLocation;
//!< clang location of the beginning of the buffer being lexed/parsed.
///@}
// const std::string* _buffer; //!< ACSL comment being parsed
// size_t _position; //!< Parsing position in the ACSL comment.
//! @name Local data members to manage the parsing
///@{
int _localStackHeight;
//!< Size of the recursive calls to readToken methods.
std::list<ErrorMessage>* _errorMessages;
//!< Refence to the Parser::_errorMessages field.
int _countErrors;
//!< Number of errors to stop the parser when it is greater than 20.
bool _doesStopOnError;
//!< Flag to stop the parser on the first encountered error.
///@}
//! @name Global parsing context coming from clang
///@{
const clang::DeclContext* _clangContext; //!< clang declarative context
const clang::ASTContext* _clangAST; //!< clang root node on the AST
clang::Sema* _clangSema;
//!< Reference to clang Sema to perform the name lookup
clang::Scope* _clangScope;
//!< clang Scope that should follow _clangContext for name lookup issues.
///@}
//! @name Local context information
///@{
const Clang_utils* _clang_utils; //!< utilities shared with FramaCIRGen.cpp
const RTTITable& _rttiTable;
//!< inheritance links between classes to manage the casts.
GlobalContext::NestedContext* _currentLogicScope;
//!< namespace and class scope enabling to store the logic constructs
//!< at the right places.
std::map<std::string, std::list<logic_var_def> > _localBinding;
//!< local \\let construct stored for finding the connected logic_var_def.
std::map<std::string, logic_type> _logicFormals;
//!< table for function formal parameters, including the implicit this.
std::set<std::string> _logicLabels; //!< Available logic labels.
enum { Unspecified, GlobalAnnot, FunSpec, CodeAnnot } _annotContext;
//!< the kind of annotation we are currently parsing
bool _result_context; //!< Can we have \\result in a term.
bool _isVerbose; //!< Does the parsing show its internal states/transitions.
///@}
friend class Parser;
template <class TypeTraits> typename TypeTraits::ResultType isTypedefType
(TypeTraits& traits, qualified_name name) const;
class IsIntegralTypeTraits;
class IsSignedTypeTraits;
class IsArithmeticTypeTraits;
class IsFloatingTypeTraits;
class IsPointerTypeTraits;
class IsReferenceTypeTraits;
class IsArrayTypeTraits;
class IsCompoundTypeTraits;
class LogicArithmeticPromotionTraits;
class MakePointedTypeTraits;
class MakeReferencedTypeTraits;
class MakeElementArrayTypeTraits;
class MakeLogicTypeTraits;
class RetrieveTypeOfFieldTraits;
class GetRecordTypeTraits;
bool addOverloadedLogicFunctionOrOperator(const std::string& name,
logic_info info, bool isMethod=false,
DLexer::OperatorPunctuatorToken::Type* codeOperator=NULL);
public:
Arguments(const clang::DeclContext* clangContext,
const clang::ASTContext* clangAST, clang::Sema* clangSema,
clang::Scope* clangScope,
Clang_utils* clang_utils, const RTTITable& rttiTable
)
:
_localStackHeight(0), _errorMessages(NULL),
_countErrors(0), _clangContext(clangContext), _clangAST(clangAST),
_clangSema(clangSema), _clangScope(clangScope),
_annotContext(Unspecified),
_lexer(clangSema),
_clang_utils(clang_utils),
_rttiTable(rttiTable),
_currentLogicScope(clang_utils->queryDeclLogicScope(clangContext)),
_result_context(false), _isVerbose(false)
{ _doesStopOnError = clang_utils->stopOnAnnotError();
_isVerbose = clang_utils->isVerbose();
}
~Arguments()
{ std::map<std::string, std::list<logic_var_def> >::iterator
iterEnd = _localBinding.end();
for (std::map<std::string, std::list<logic_var_def> >::iterator
iter = _localBinding.begin(); iter != iterEnd; ++iter) {
std::list<logic_var_def>::iterator subiterEnd = iter->second.end();
for (std::list<logic_var_def>::iterator
subiter = iter->second.begin(); subiter != subiterEnd; ++subiter)
free_logic_var_def(*subiter);
iter->second.clear();
};
}
// Getter and setter methods
void resetAnnotContext() { _annotContext = Unspecified; }
void setGlobalAnnotContext() { _annotContext = GlobalAnnot; }
void setFunSpecContext() { _annotContext = FunSpec; }
void setCodeAnnotContext() { _annotContext = CodeAnnot; }
bool isGlobalAnnotContext() const { return _annotContext == GlobalAnnot; }
bool isFunSpecContext() const { return _annotContext == FunSpec; }
bool isCodeAnnotContext () const { return _annotContext == CodeAnnot; }
void setDoesStopOnError() { _doesStopOnError = true; }
const clang::DeclContext* getDeclContext() { return _clangContext; }
bool isExternCContext() { return _clang_utils->isExternCContext(_clangContext); }
const GlobalContext::NestedContext* getLogicContext() { return _currentLogicScope; }
const Clang_utils* get_clang_utils() { return _clang_utils; }
Lexer& lexer() { return _lexer; }
Lexer::AbstractToken queryToken() { return _lexer.queryToken(); }
const Lexer::AbstractToken& getContentToken() const { return _lexer.getContentToken(); }
// Parser methods
void shift() { ++_localStackHeight; }
void reduce() { --_localStackHeight; }
int getNewVarNumber() { return ++_clang_utils->logicVariableNumber(); }
//! Adds an error message to _errorMessages with the given message
//! and the position of the most recent lexer token
bool addErrorMessage(const std::string& message) {
return addErrorMessage(message, _lexer.seeTokenLocation());
}
//! Adds an error message to _errorMessages with the given message and location
//!
bool addErrorMessage(const std::string& message, location tokenLocation);
bool doesStopAfterTooManyErrors() const
{ return (_doesStopOnError || !_errorMessages || _countErrors >= 20); } // FIXME - allow user to set this number?
//! Moves accumulated error messages from lexer to parser
//!
void addErrorMessagesFromLexer();
/**
* @brief a shortcut function to call the lexer inside the parser.
*
* With this function, call/return to the Parser::parse function are
* translated into goto, call, return inside the readToken function
* of components.
* To debug the parsing, it may be convenient to return false. That
* enables to count the tokens issued from the lexer and so to find
* the exact rule that is likely to produce inadequate results.
*/
void eatToken(ReadResult& result);
bool setToNextToken(ReadResult& result)
{
bool booleanResult = false;
if (isValidRange()) {
if (_lexer.doesNeedClear())
_lexer.clearToken();
do {
_lexer.eatToken(result);
} while (result == RRContinueLexing);
booleanResult = (result == RRHasToken);
}
else
result = RRNeedChars;
if (!booleanResult)
clearRange();
return booleanResult;
}
/*! Makes a copy of the current token location */
location newTokenLocation() const { return copy_loc(_tokenLocation); }
/*! copies the end position of the current token location into the end position in the argument */
void extendLocationWithToken(location loc) const {
extend_location_with(loc,_tokenLocation); }
/*! Converts the current token location to an equivalent clang SourceLocation */
clang::SourceLocation tokenSourceLocation() const
{ return _clang_utils->getSourceLocation(_tokenLocation); }
bool isValidRange() const
{ return _isVerbose ? false
: (_localStackHeight >= 0 && _localStackHeight <= 7);
}
void clearRange() { _localStackHeight = 0; }
bool hasErrors() const
{ return _errorMessages && !_errorMessages->empty(); }
std::list<ErrorMessage>& errors() const
{ assert(_errorMessages); return *_errorMessages; }
/// outputs existing error messages before failing with assert(false)
bool fail () const {
std::list<ErrorMessage>& msgs = errors();
std::list<ErrorMessage>::const_iterator iterEnd = msgs.end();
for (std::list<ErrorMessage>::const_iterator iter = msgs.begin();
iter != iterEnd; ++iter)
std::cerr << iter->filepos() << ':' << iter->linepos() << ':'
<< iter->columnpos() << ": "
<< iter->getMessage() << std::endl;
msgs.clear();
return false;
}
const clang::NamedDecl* isCodeName(const std::string& name,
const clang::TemplateArgument** templateArgument=NULL,
bool* hasOverload=NULL) const;
const clang::NamedDecl* findQualifiedName(const std::string& name,
const clang::DeclContext* context, bool* hasOverload=NULL) const;
bool isIntegralTypedefType(qualified_name name) const;
bool isSignedTypedefType(qualified_name name) const;
bool isArithmeticTypedefType(qualified_name name) const;
bool isFloatingTypedefType(qualified_name name) const;
bool isPointerTypedefType(qualified_name name) const;
bool isReferenceTypedefType(qualified_name name) const;
bool isArrayTypedefType(qualified_name name) const;
bool is_char_signed() const;
bool is_wchar_signed() const;
qualified_name makeCompoundTypedefType(qualified_name name,
tkind* templateKind) const;
logic_type makeTypeOfPointed(qualified_name name) const;
logic_type makeTypeOfReferenced(qualified_name name) const;
logic_type makeTypeOfArrayElement(qualified_name name) const;
const clang::RecordType* getRecordType(qualified_name name) const;
bool addOverloadedLogicFunctions(const std::string& name, logic_info info,
bool isMethod=false)
{ return addOverloadedLogicFunctionOrOperator(name, info, isMethod); }
bool addOverloadedLogicOperators(const std::string& name,
DLexer::OperatorPunctuatorToken::Type typeOperator, logic_info info,
bool isMethod=false)
{ return addOverloadedLogicFunctionOrOperator(name, info, isMethod,
&typeOperator);
}
bool addLogicType(const std::string& name, logic_type_info ltypeInfo);
GlobalContext::LogicType* findGlobalLogicType(qualified_name name) const;
GlobalContext::LogicVariable* findGlobalLogicVariable(qualified_name name)
const;
GlobalContext::NestedContext* findGlobalLogicName(qualified_name name) const
{ return _clang_utils->globalAcslContext().findAbsolute(name); }
GlobalContext::NestedContext* findLogicName(const std::string& name) const
{ return _clang_utils->globalAcslContext().find(name, _currentLogicScope);
}
GlobalContext::NestedContext* findLogicName(qualified_name context,
const std::string& name, tkind* templateParameterContext=NULL) const;
/* qualification */ list createPrequalification() const;
GlobalContext::NestedContext* findLogicQualifiedName(
const std::string& name, GlobalContext::NestedContext* scope) const
{ const GlobalContext::NestedContext::SonsSet* sons = scope
? scope->ssons() : &_clang_utils->globalAcslContext().logicTable();
GlobalContext::NestedContext* result = NULL;
if (sons) {
GlobalContext::NestedContext locate(name);
GlobalContext::NestedContext::SonsSet::const_iterator
found = sons->find(&locate);
result = (found != sons->end()) ? *found : NULL;
};
return result;
}
logic_type boolean_type() const {
qualification logic_ns = qualification_QNamespace("Utf8_logic");
qualified_name boolean =
qualified_name_cons(cons_container(logic_ns,NULL),"boolean");
GlobalContext::LogicType* def = findGlobalLogicType(boolean);
assert(def);
logic_type_info info = def->type_info();
return logic_type_Lnamed(qualified_name_dup(info->type_name),false,NULL);
}
bool is_builtin_boolean(logic_type t) const {
static logic_type default_boolean_type = boolean_type();
return logic_type_equal(default_boolean_type,t);
}
bool isLogicSetType(logic_type typ) const {
return
typ->tag_logic_type == LNAMED &&
strcmp(typ->cons_logic_type.Lnamed.name->decl_name,"set") == 0;
}
logic_type type_of_element(logic_type typ) const {
assert (isLogicSetType(typ));
return
(logic_type)
typ->cons_logic_type.Lnamed.template_arguments->element.container;
}
logic_type logicArithmeticPromotion(qualified_name name) const;
logic_type makeLogicType(qualified_name name) const;
qualified_name makeLogicQualifiedName(const std::string& name) const;
/** Outside of a class, returns NULL. Inside a class,
it returns the type corresponding to the this pointer when in a
code annotation or function contract, and to the \this object when
in a global annotation.
*/
logic_type queryThisType() const;
/** Outside of a class, returns NULL. Inside a class, returns the object
*this (when in a code annotation or function constract) or \this
(when in a global annotation)
*/
term_lval thisLval() const;
bool retrieveTypeOfField(qualified_name name, tkind templateParameters,
const std::string& fieldName, term_offset& offset, logic_type& ltype,
std::string& errorMessage);
logic_var_def hasLocalBinding(const std::string& name) const
{ std::map<std::string, std::list<logic_var_def> >::const_iterator
found = _localBinding.find(name);
return (found != _localBinding.end()) ? found->second.back() : NULL;
}
void addLocalBinding(const std::string& name, logic_var_def definition)
{ std::map<std::string, std::list<logic_var_def> >::iterator
found = _localBinding.find(name);
if (found == _localBinding.end())
found = _localBinding.insert(std::make_pair(name,
std::list<logic_var_def>())).first;
found->second.push_back(definition);
}
void removeLocalBinding(const std::string& name)
{ std::map<std::string, std::list<logic_var_def> >::iterator
found = _localBinding.find(name);
if (found != _localBinding.end()) {
free_logic_var_def(found->second.back());
found->second.pop_back();
if (found->second.empty())
_localBinding.erase(found);
};
}
logic_type hasLogicFormal(const std::string& name) const
{ std::map<std::string, logic_type>::const_iterator found =
_logicFormals.find(name);
return (found != _logicFormals.end())?found->second:NULL;
}
void addLogicFormal(const std::string& name, logic_type type)
{ _logicFormals.insert(std::make_pair(name,type)); }
void removeLogicFormal(const std::string& name)
{ _logicFormals.erase(name); }
void addLogicLabel(const std::string& name) { _logicLabels.insert(name); }
void removeLogicLabel(const std::string& name)
{ std::set<std::string>::iterator found = _logicLabels.find(name);
if (found != _logicLabels.end())
_logicLabels.erase(found);
}
logic_label findLogicLabel(const std::string& name) const;
void set_result_context(bool flag) { _result_context = flag; }
logic_type createResultType() const;
bool isVerbose() const { return _isVerbose; }
void setVerbose() { _isVerbose = true; }
};
typedef ::Parser::TStateStack<Arguments> State;
private:
/*! @brief Current state of the parser.
*
* This field is a stack of state machines. The current state machine can
* go to another local state. It can shift, that is it pushes a new state
* machine onto the stack _state. It can reduce, that is it pops the last
* state machine from the stack _state
*/
State _state;
/*! @brief Global services to help the CIL AST construction methods.
*
* These services are to be called by _state.parse = readToken methods
* of the components.
*/
void addBuiltinBinding(const std::string& ident, logic_type ret_type, std::initializer_list<logic_type> args);
// void addBuiltinBinding(const std::string& ident, logic_type ret_type, logic_type arg0);
// void addBuiltinBinding(const std::string& ident, logic_type ret_type, logic_type arg0, logic_type arg1);
void addBuiltinBindings(void);
Arguments _arguments;
std::list<ErrorMessage> _errorMessages; //!< List of the error messages.
public:
template <class TypeObject>
Parser(const clang::DeclContext* clangContext,
const clang::ASTContext* clangAST, clang::Sema* clangSema,
clang::Scope* clangScope,
Clang_utils* clang_utils, TypeObject& object, const RTTITable& rttiTable)
: _arguments(clangContext, clangAST, clangSema, clangScope,
clang_utils, rttiTable)
{ _state.shift(object, &TypeObject::readToken); addBuiltinBindings(); _arguments._errorMessages = &_errorMessages; }
State& state() { return _state; }
const State& state() const { return _state; }
const std::list<ErrorMessage>& errorMessages() const
{ return _errorMessages; }
bool hasError() const { return !_errorMessages.empty(); }
void parse(const std::string& buffer, const clang::SourceLocation& sourceLocation);
Lexer& lexer() { return _arguments.lexer(); }
};
} // end of namespace Acsl
#define DefineParseCase(Delim) \
case D##Delim: \
L##Delim:
#define DefineInitParseCase(Delim) \
case D##Delim: \
#define DefineGotoCase(Delim) \
{ state.point() = D##Delim; \
if (arguments.isVerbose()) { \
std::cout << "** token \""; \
arguments.lexer().assumeContentToken(); \
arguments.getContentToken().write(std::cout, \
AbstractToken::PersistentFormat().setPretty()); \
std::cout << "\" parsed, goto state (" #Delim ")" << std::endl; \
}; \
if (arguments.setToNextToken(result)) goto L##Delim; \
return result; \
}
#define DefineGotoCaseWithIncrement(Increment, LabelTarget) \
{ state.point() += Increment; \
if (arguments.isVerbose()) { \
std::cout << "** token \""; \
arguments.lexer().assumeContentToken(); \
arguments.getContentToken().write(std::cout, \
AbstractToken::PersistentFormat().setPretty()); \
std::cout << "\" parsed, goto state" << state.point() << std::endl; \
}; \
if (arguments.setToNextToken(result)) goto LabelTarget; \
return result; \
}
#define DefineGotoCaseAndParse(Delim) \
{ state.point() = D##Delim; \
if (arguments.isVerbose()) \
std::cout << "** goto state (" #Delim ")" << std::endl; \
goto L##Delim; \
}
#define DefineGotoCaseAndParseWithIncrement(Increment, LabelTarget) \
{ state.point() += Increment; \
if (arguments.isVerbose()) \
std::cout << "** goto state (" \
<< state.point() << ")" << std::endl; \
goto LabelTarget; \
}
#define DefineShift(Delim, Object, MethodPointer) \
{ arguments.shift(); \
state.point() = D##Delim; \
state.shift(Object, MethodPointer); \
if (arguments.isVerbose()) { \
std::cout << "** token \""; \
arguments.lexer().assumeContentToken(); \
arguments.getContentToken().write(std::cout, \
AbstractToken::PersistentFormat().setPretty()); \
std::cout << "\" parsed, call " << #MethodPointer \
<< ", next is (" #Delim ")" << std::endl; \
}; \
if (arguments.setToNextToken(result)) { \
result = (Object).readToken(state, arguments); \
if (result == RRContinueParsing) { \
result = RRNeedChars; \
state.point() = D##Delim; \
goto L##Delim; \
}; \
}; \
return result; \
}
#define DefineShiftFrom(Delim, Point, Object, MethodPointer) \
{ arguments.shift(); \
state.point() = D##Delim; \
state.shift(Object, MethodPointer); \
state.point() = Point; \
if (arguments.isVerbose()) { \
std::cout << "** token \""; \
arguments.lexer().assumeContentToken(); \
arguments.getContentToken().write(std::cout, \
AbstractToken::PersistentFormat().setPretty()); \
std::cout << "\" parsed, call " << #MethodPointer << ':' \
<< Point << ", next is (" #Delim ")" << std::endl; \
}; \
if (arguments.setToNextToken(result)) { \
result = (Object).readToken(state, arguments); \
if (result == RRContinueParsing) { \
result = RRNeedChars; \
state.point() = D##Delim; \
goto L##Delim; \
}; \
}; \
return result; \
}
#define DefineShiftWithIncrement(Increment, LabelTarget, Object, MethodPointer)\
{ arguments.shift(); \
state.point() += Increment; \
state.shift(Object, MethodPointer); \
if (arguments.isVerbose()) { \
std::cout << "** token \""; \
arguments.lexer().assumeContentToken(); \
arguments.getContentToken().write(std::cout, \
AbstractToken::PersistentFormat().setPretty()); \
std::cout << "\" parsed, call " << #MethodPointer \
<< ", next is " << state.point() << std::endl; \
}; \
if (arguments.setToNextToken(result)) { \
result = (Object).readToken(state, arguments); \
if (result == RRContinueParsing) { \
result = RRNeedChars; \
goto LabelTarget; \
}; \
}; \
return result; \
}
#define DefineShiftAndParse(Delim, Object, MethodPointer) \
{ arguments.shift(); \
state.point() = D##Delim; \
state.shift(Object, MethodPointer); \
if (arguments.isVerbose()) \
std::cout << "** call " << #MethodPointer \
<< ", next is (" #Delim ")" << std::endl; \
if (arguments.isValidRange()) \
result = (Object).readToken(state, arguments); \
else { \
arguments.clearRange(); \
result = state.parse(arguments); \
}; \
if (result == RRContinueParsing) { \
result = RRNeedChars; \
state.point() = D##Delim; \
goto L##Delim; \
}; \
return result; \
}
#define DefineShiftAndParseFrom(Delim, Point, Object, MethodPointer) \
{ arguments.shift(); \
state.point() = D##Delim; \
state.shift(Object, MethodPointer); \
state.point() = Point; \
if (arguments.isVerbose()) \
std::cout << "** call " << #MethodPointer << ':' << Point \
<< ", next is (" #Delim ")" << std::endl; \
if (arguments.isValidRange()) \
result = (Object).readToken(state, arguments); \
else { \
arguments.clearRange(); \
result = state.parse(arguments); \
}; \
if (result == RRContinueParsing) { \
result = RRNeedChars; \
state.point() = D##Delim; \
goto L##Delim; \
}; \
return result; \
}
#define DefineReduce \
{ arguments.reduce(); \
state.reduce(); \
if (arguments.isVerbose()) { \
std::cout << "** token \""; \
arguments.lexer().assumeContentToken(); \
arguments.getContentToken().write(std::cout, \
AbstractToken::PersistentFormat().setPretty()); \
std::cout << "\" parsed, reduction" << std::endl; \
}; \
if (arguments.setToNextToken(result) && result == RRNeedChars) \
result = RRContinueParsing; \
return result; \
}
#define DefineTReduce \
{ arguments.extendLocationWithToken(_loc); \
arguments.reduce(); \
state.reduce(); \
if (arguments.isVerbose()) { \
std::cout << "** token \""; \
arguments.lexer().assumeContentToken(); \
arguments.getContentToken().write(std::cout, \
AbstractToken::PersistentFormat().setPretty()); \
std::cout << "\" parsed, reduction" << std::endl; \
}; \
if (arguments.setToNextToken(result) && result == RRNeedChars) \
result = RRContinueParsing; \
return result; \
}
#define DefineReduceAndParse \
{ arguments.reduce(); \
state.reduce(); \
if (arguments.isVerbose()) \
std::cout << "** reduction" << std::endl; \
if (arguments.isValidRange() && result == RRNeedChars) \
result = RRContinueParsing; \
else { \
arguments.clearRange(); \
result = state.parse(arguments); \
}; \
return result; \
}
#define DefineAddError(Message) \
{ if (!arguments.addErrorMessage(Message)) \
return RRFinished; \
}
#define DefineAddErrorAndParse(Message) \
{ if (!arguments.addErrorMessage(Message)) \
return RRFinished; \
arguments.clearRange(); \
return RRNeedChars; \
}
#endif // ACSL_ParserH