OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
OpalParser.cpp
Go to the documentation of this file.
1
2// ------------------------------------------------------------------------
3// $RCSfile: OpalParser.cpp,v $
4// ------------------------------------------------------------------------
5// $Revision: 1.3 $
6// ------------------------------------------------------------------------
7// Copyright: see Copyright.readme
8// ------------------------------------------------------------------------
9//
10// Class OpalParser:
11// This is the default parser for OPAL statements.
12//
13// ------------------------------------------------------------------------
14//
15// $Date: 2001/08/13 15:17:27 $
16// $Author: jowett $
17//
18// ------------------------------------------------------------------------
19
31
32#include <cmath>
33#include <ctime>
34#include <exception>
35#include <iostream>
36#include <memory>
37#include <new>
39#include "OpalParser/Token.h"
41#include "Utilities/Options.h"
43
44#include "Utility/Inform.h"
45#include "Utility/IpplInfo.h"
46
47using namespace Expressions;
48
49extern Inform* gmsg;
50
51// Class OpalParser
52// ------------------------------------------------------------------------
53
54std::vector<std::shared_ptr<TokenStream> > OpalParser::inputStack;
55
56OpalParser::OpalParser() : stopFlag(false) {}
57
59
60void OpalParser::parse(Statement& stat) const {
61 if (stat.keyword("SHARED")) {
62 // "SHARED ...": Shared object definition.
63 parseDefine(stat);
64 } else if (
65 stat.keyword("CONSTANT") || stat.keyword("CONST") || stat.keyword("BOOL")
66 || stat.keyword("REAL") || stat.keyword("STRING") || stat.keyword("VECTOR")) {
67 // Keywords introducing variable definitions.
68 parseAssign(stat);
69 } else {
70 std::string name = parseString(stat, "Identifier or keyword expected.");
71
72 if (stat.delimiter('?')) {
73 // "<class>?": give help for class.
74 printHelp(name);
75 } else if (stat.delimiter(':')) {
76 // "<object>:<class>...": labeled command.
77 parseDefine(stat);
78 } else if (stat.delimiter('(')) {
79 // "<macro>(...)...": macro definition or call.
80 // We are positioned just after the '(' of the argument list.
81 parseMacro(name, stat);
82 } else if (stat.delimiter(',') || stat.delimiter(';') || stat.atEnd()) {
83 // "<class>" or "<class>,<attributes>": Executable command.
84 parseAction(stat);
85 } else {
86 // Assignment beginning with a name.
87 stat.mark();
88 stat.start();
89 std::string objName = parseString(stat, "Object name expected.");
90 if (OpalData::getInstance()->find(objName) == 0) {
91 Token tok = stat.getCurrent();
92 stat.restore();
93
94 std::string name = tok.getLex();
95 std::string hint = getHint(name);
96 unsigned int position = stat.position();
97 std::string positionIndicator = std::string(position, ' ') + "^\n";
98 std::ostringstream statStr;
99 stat.print(statStr);
100 if (!hint.empty()) {
101 throw ParseError(
102 "OpalParser::parse()",
103 statStr.str() + positionIndicator
104 + "Syntax error, either the keyword REAL is missing or\n"
105 + hint);
106 } else {
107 throw ParseError(
108 "OpalParser::parse()",
109 statStr.str() + positionIndicator
110 + "Syntax error, the keyword REAL is missing\n");
111 }
112 }
113 parseAssign(stat);
114 }
115 }
116}
117
118void OpalParser::execute(Object* object, const std::string& name) const {
119 // Trace execution.
120 if (Options::mtrace && object->shouldTrace()) {
121 double time = double(clock()) / double(CLOCKS_PER_SEC);
122 *gmsg << "\nBegin execution: \"" << name << "\", CPU time = " << time << " seconds.\n"
123 << endl;
124 }
125
126 // Force updating of all attributes which might have been changed.
127 if (object->shouldUpdate()) {
129 }
130
131 // Execute or check the command.
132 object->execute();
133
134 // Trace execution.
135 if (Options::mtrace && object->shouldTrace()) {
136 double time = double(clock()) / double(CLOCKS_PER_SEC);
137 *gmsg << "\nEnd execution: \"" << name << "\", CPU time = " << time << " seconds.\n"
138 << endl;
139 }
140}
141
142Object* OpalParser::find(const std::string& name) const {
143 return OpalData::getInstance()->find(name);
144}
145
147 stat.start();
148 std::string cmdName = parseString(stat, "Command name expected");
149
150 if (cmdName == "STOP") {
151 stopFlag = true;
152 } else if (cmdName == "QUIT") {
153 stopFlag = true;
154 } else if (cmdName == "HELP" && stat.delimiter(',')) {
155 cmdName = parseString(stat, "Object name expected");
156 printHelp(cmdName);
157 } else if (Object* object = find(cmdName)) {
158 Object* copy = 0;
159 try {
160 copy = object->clone("");
161 copy->parse(stat);
162 parseEnd(stat);
163 execute(copy, cmdName);
164 delete copy;
165 } catch (...) {
166 delete copy;
167 throw;
168 }
169 } else {
170 std::string hint = getHint(cmdName, "command");
171 if (!hint.empty()) {
172 throw ParseError("OpalParser::parseAction()", "Syntax error, " + hint);
173 }
174
175 throw ParseError("OpalParser::parseAction()", "Command \"" + cmdName + "\" is unknown.");
176 }
177}
178
180 stat.start();
181
182 // Find various model objects.
183 /*static*/
184 Object* boolConstant = OpalData::getInstance()->find("BOOL_CONSTANT");
185 /*static*/
186 Object* realConstant = OpalData::getInstance()->find("REAL_CONSTANT");
187 /*static*/
188 Object* realVariable = OpalData::getInstance()->find("REAL_VARIABLE");
189 /*static*/
190 Object* realVector = OpalData::getInstance()->find("REAL_VECTOR");
191 /*static*/
192 Object* stringConstant = OpalData::getInstance()->find("STRING_CONSTANT");
193
194 // Gobble up any prefix.
195 int code = 0x00;
196 while (true) {
197 if (stat.keyword("CONSTANT") || stat.keyword("CONST")) {
198 code |= 0x01;
199 } else if (stat.keyword("BOOL")) {
200 code |= 0x02;
201 } else if (stat.keyword("REAL")) {
202 code |= 0x04;
203 } else if (stat.keyword("STRING")) {
204 code |= 0x08;
205 } else if (stat.keyword("VECTOR")) {
206 code |= 0x10;
207 } else {
208 break;
209 }
210 }
211
212 std::string objName = parseString(stat, "Object name expected.");
213 // Test for attribute name.
214 Object* object = 0;
215 std::string attrName;
216
217 if (stat.delimiter("->")) {
218 // Assignment to object attribute.
219 attrName = parseString(stat, "Attribute name expected.");
220
221 if (code != 0) {
222 throw ParseError(
223 "OpalParser::parseAssign()", "Invalid type specification for this value.");
224 } else if ((object = OpalData::getInstance()->find(objName)) == 0) {
225 throw ParseError(
226 "OpalParser::parseAssign()", "The object \"" + objName + "\" is unknown.");
227 }
228 } else {
229 // Assignment to variable-like object.
230 if ((object = OpalData::getInstance()->find(objName)) == 0) {
231 Object* model = 0;
232 switch (code) {
233 case 0x01: // CONSTANT
234 case 0x05: // CONSTANT REAL
235 model = realConstant;
236 break;
237 case 0x02: // BOOL
238 case 0x03: // BOOL CONSTANT
239 model = boolConstant;
240 break;
241 case 0x00: // empty <type>.
242 case 0x04: // REAL
243 model = realVariable;
244 break;
245 case 0x10: // VECTOR
246 case 0x11: // CONSTANT VECTOR
247 case 0x14: // REAL VECTOR
248 case 0x15: // CONSTANT REAL VECTOR
249 model = realVector;
250 break;
251 case 0x08: // STRING
252 case 0x09: // STRING CONSTANT
253 model = stringConstant;
254 break;
255 default:
256 break;
257 }
258
259 if (model != 0) {
260 object = model->clone(objName);
261 OpalData::getInstance()->define(object);
262 } else {
263 throw ParseError("OpalParser::parseAssign()", "Invalid <type> field.");
264 }
265 } else if (object->isTreeMember(realConstant)) {
266 throw ParseError(
267 "OpalParser::parseAssign()",
268 "You cannot redefine the constant \"" + objName + "\".");
269 }
270
271 attrName = "VALUE";
272 }
273
274 // Test for index; it is evaluated immediately.
275 int index = 0;
276
277 if (stat.delimiter('[')) {
278 index = int(std::round(parseRealConst(stat)));
279 parseDelimiter(stat, ']');
280
281 if (index <= 0) {
282 throw ParseError("Expressions::parseReference()", "Index must be positive.");
283 }
284 }
285
286 if (object != 0) {
287 if (Attribute* attr = object->findAttribute(attrName)) {
288 if (stat.delimiter('=') || object->isTreeMember(realConstant)) {
289 if (index > 0) {
290 attr->parseComponent(stat, true, index);
291 } else {
292 attr->parse(stat, true);
293 }
294 } else if (stat.delimiter(":=")) {
295 if (index > 0) {
296 attr->parseComponent(stat, false, index);
297 } else {
298 attr->parse(stat, false);
299 }
300 }
301 } else {
302 throw ParseError(
303 "OpalParser::parseAssign()",
304 "Object \"" + objName + "\" has no attribute \"" + attrName + "\".");
305 }
306
307 parseEnd(stat);
309 }
310}
311
313 stat.start();
314 bool isShared = stat.keyword("SHARED");
315 std::string objName = parseString(stat, "Object name expected.");
316
317 if (stat.delimiter(':')) {
318 std::string clsName = parseString(stat, "Class name expected.");
319 Object* classObject = find(clsName);
320
321 if (classObject == 0) {
322 if (clsName == "SURFACEPHYSICS")
323 throw ParseError(
324 "OpalParser::parseDefine()",
325 "The object \"" + clsName
326 + "\" is changed to \"PARTICLEMATTERINTERACTION\".");
327 else
328 throw ParseError(
329 "OpalParser::parseDefine()", "The object \"" + clsName + "\" is unknown.");
330 }
331
332 Object* copy = 0;
333 try {
334 if (stat.delimiter('(')) {
335 // Macro-like objects are always classes, instances never.
336 // There is no further check required.
337 copy = classObject->makeInstance(objName, stat, this);
338 } else {
339 copy = classObject->clone(objName);
340 copy->parse(stat);
341 copy->setShared(isShared);
342 }
343
344 parseEnd(stat);
345 execute(copy, clsName);
347 } catch (...) {
348 delete copy;
349 throw;
350 }
351 } else {
352 // Redefine an object to be a class.
353 Object* classObject = find(objName);
354 Object* copy = classObject->clone(objName);
355 copy->parse(stat);
356 copy->setShared(isShared);
357 }
358}
359
361 if (!stat.atEnd() && !stat.delimiter(';')) {
362 unsigned int position = stat.position();
363 std::string positionIndicator = std::string(position + 1, ' ') + "^\n";
364 std::ostringstream statStr;
365 stat.print(statStr);
366
367 throw ParseError(
368 "OpalParser::parseEnd()",
369 statStr.str() + positionIndicator
370 + "Syntax error (maybe missing comma or semicolon ? )");
371 }
372}
373
374void OpalParser::parseMacro(const std::string& macName, Statement& stat) const {
375 // Record the position just after the '(' of the argument list.
376 stat.mark();
377
378 // Skip argument list.
379 int par_level = 1;
380 while (true) {
381 if (stat.delimiter('(')) {
382 ++par_level;
383 } else if (stat.delimiter(')')) {
384 if (--par_level == 0) break;
385 } else {
386 stat.getCurrent();
387 }
388 }
389
390 if (stat.delimiter(':')) {
391 // Macro definition.
392 std::string className = parseString(stat, "Class name expected.");
393
394 if (Object* macro = OpalData::getInstance()->find(className)) {
395 // Backtrack to first argument.
396 stat.restore();
397
398 if (Object* copy = macro->makeTemplate(macName, *inputStack.back(), stat)) {
400 } else {
401 throw ParseError(
402 "OpalParser::parseMacro()",
403 "Command \"" + macName + "\" cannot be defined with arguments.");
404 }
405 } else {
406 throw ParseError(
407 "OpalParser::parseMacro()", "Object \"" + className + "\" is unknown.");
408 }
409 } else {
410 // Macro call.
411 if (Object* macro = OpalData::getInstance()->find(macName)) {
412 // Backtrack to first argument.
413 stat.restore();
414 Object* instance = 0;
415 try {
416 instance = macro->makeInstance(macName, stat, this);
417 execute(instance, macName);
418 } catch (...) {
419 delete instance;
420 throw;
421 }
422 } else {
423 throw ParseError("OpalParser::parseMacro()", "Macro \"" + macName + "\" is unknown.");
424 }
425 }
426}
427
428void OpalParser::printHelp(const std::string& cmdName) const {
429 Object* object = find(cmdName);
430
431 if (object == 0) {
432 *gmsg << "\nOpalParser::printHelp(): Unknown object \"" << cmdName << "\".\n" << endl;
433 } else {
434 object->printHelp(std::cerr);
435 }
436}
437
439 Token token = readToken();
440
441 while (!token.isEOF()) {
442 stat.append(token);
443
444 if (token.isDel('(')) {
445 parseBracketList(')', stat);
446 } else if (token.isDel('[')) {
447 parseBracketList(']', stat);
448 } else if (token.isDel('{')) {
449 parseBracketList('}', stat);
450 } else if (token.isDel(close)) {
451 return;
452 }
453
454 token = readToken();
455 }
456}
457
459 Token token = readToken();
460
461 while (!token.isEOF()) {
462 // End of list if semicolon occurs outside of brackets.
463 if (token.isDel(';')) break;
464 stat.append(token);
465
466 if (token.isDel('(')) {
467 parseBracketList(')', stat);
468 } else if (token.isDel('[')) {
469 parseBracketList(']', stat);
470 } else if (token.isDel('{')) {
471 parseBracketList('}', stat);
472 }
473
474 token = readToken();
475 }
476}
477
479 if (inputStack.empty()) {
480 return Token("", 0, Token::IS_EOF, "End of input");
481 } else {
482 return inputStack.back()->readToken();
483 }
484}
485
487 Statement* stat = 0;
488 Token token = is->readToken();
489
490 try {
491 if (token.isDel('{')) {
492 // Compound statement.
493 inputStack.back()->putBack(token);
494 stat = new CompoundStatement(*inputStack.back());
495 } else if (token.isKey("IF")) {
496 // IF statement.
497 inputStack.back()->putBack(token);
498 stat = new IfStatement(*this, *inputStack.back());
499 } else if (token.isKey("WHILE")) {
500 // WHILE statement.
501 inputStack.back()->putBack(token);
502 stat = new WhileStatement(*this, *inputStack.back());
503 } else if (token.isWord() || token.isString()) {
504 // Simple statement or MACRO statement.
505 stat = new SimpleStatement(token.getFile(), token.getLine());
506 stat->append(token);
507 token = is->readToken();
508
509 if (!token.isEOF()) {
510 if (token.isDel('(')) {
511 // Macro statement; statement already contains initial word.
512 stat->append(token);
513 parseBracketList(')', *stat);
514 token = is->readToken();
515
516 if (!token.isEOF() && token.isDel(':')) {
517 // Macro definition.
518 stat->append(token);
519 token = is->readToken();
520
521 if (!token.isEOF()) {
522 stat->append(token);
523 if (token.isKey("MACRO")) {
524 token = is->readToken();
525
526 if (!token.isEOF() && token.isDel('{')) {
527 stat->append(token);
528 parseBracketList('}', *stat);
529 } else {
530 throw ParseError(
531 "OpalParser::readStatement()",
532 "MACRO definition lacks \"{...}\".");
533 }
534 } else {
535 parseTokenList(*stat);
536 }
537 }
538 } else if (!token.isDel(';')) {
539 throw ParseError(
540 "OpalParser::readStatement()",
541 "MACRO call is not terminated by ';'.");
542 }
543 } else if (!token.isDel(';')) {
544 stat->append(token);
545 parseTokenList(*stat);
546 }
547 }
548 stat->start();
549 } else if (token.isDel(';')) {
550 // Skip empty statement.
551 stat = readStatement(is);
552 } else if (token.isDel('?')) {
553 // Give help.
554 *gmsg << "\ntry typing \"HELP\" for help.\n" << endl;
555 stat = readStatement(is);
556 } else if (!token.isEOF()) {
557 stat = new SimpleStatement(token.getFile(), token.getLine());
558 stat->append(token);
559 parseTokenList(*stat);
560 stat->start();
561 throw ParseError("OpalParser::readStatement()", "Command should begin with a <name>.");
562 }
563 } catch (ParseError& ex) {
564 *ippl::Error << "\n*** Parse error detected by function \""
565 << "OpalParser::readStatement()"
566 << "\"\n";
568
569 std::string what = ex.what();
570 std::string::size_type pos = 0;
571 while ((pos = what.find("\n", pos)) != std::string::npos) {
572 what.replace(pos, 1, "\n ");
573 pos += 5; // length of "\n "
574 }
575
576 *ippl::Error << " " << *stat << " a" << what << '\n' << endl;
577
578 stat = readStatement(is);
579 exit(1);
580 }
581
582 return stat;
583}
584
585void OpalParser::run() const {
586 stopFlag = false;
587 while (Statement* stat = readStatement(&*inputStack.back())) {
588 try {
589 // The dispatch via Statement::execute() allows a special
590 // treatment of structured statements.
591 stat->execute(*this);
592 } catch (ParseError& ex) {
593 Inform errorMsg("Error", std::cerr);
594 errorMsg << "\n*** Parse error detected by function \"" << ex.where() << "\"\n";
595 stat->printWhere(errorMsg, true);
596 std::string what = ex.what();
597 size_t pos = what.find_first_of('\n');
598 do {
599 errorMsg << " " << what.substr(0, pos) << endl;
600 what = what.substr(pos + 1, std::string::npos);
601 pos = what.find_first_of('\n');
602 } while (pos != std::string::npos);
603 errorMsg << " " << what << endl;
604
605 MPI_Abort(MPI_COMM_WORLD, -100);
606 }
607
608 delete stat;
609 if (stopFlag) break;
610 }
611}
612
614 inputStack.push_back(std::shared_ptr<TokenStream>(is));
615 run();
616 inputStack.pop_back();
617}
618
619void OpalParser::stop() const { stopFlag = true; }
620
621std::string OpalParser::getHint(const std::string& name, const std::string& type) {
622 auto owner = AttributeHandler::getOwner(name);
623 if (owner.empty()) {
624 return std::string();
625 }
626
627 std::string hint = "the " + type + " '" + name + "' could belong to\n";
628 {
629 std::string elements;
630 auto its = owner.equal_range(AttributeHandler::ELEMENT);
631 if (its.first != its.second) {
632 elements = (its.first)->second;
633 bool any = (its.first)->second == "Any";
634 for (auto it = std::next(its.first); it != its.second && !any; ++it) {
635 elements += ", " + it->second;
636 any = it->second == "Any";
637 }
638 if (any) {
639 hint += std::string(" - any element\n");
640 } else {
641 hint += std::string(" - the element")
642 + (std::distance(its.first, its.second) > 1 ? "s " : " ") + elements + "\n";
643 }
644 }
645 }
646 {
647 std::string commands;
648 auto its = owner.equal_range(AttributeHandler::COMMAND);
649 if (its.first != its.second) {
650 commands = (its.first)->second;
651 for (auto it = std::next(its.first); it != its.second; ++it) {
652 commands += ", " + it->second;
653 }
654 hint += std::string(" - the command")
655 + (std::distance(its.first, its.second) > 1 ? "s " : " ") + commands + "\n";
656 }
657 }
658 {
659 std::string sub_commands;
660 auto its = owner.equal_range(AttributeHandler::SUB_COMMAND);
661 if (its.first != its.second) {
662 sub_commands = (its.first)->second;
663 for (auto it = std::next(its.first); it != its.second; ++it) {
664 sub_commands += ", " + it->second;
665 }
666 hint += std::string(" - the sub-command")
667 + (std::distance(its.first, its.second) > 1 ? "s " : " ") + sub_commands + "\n";
668 }
669 }
670 {
671 std::string statements;
672 auto its = owner.equal_range(AttributeHandler::STATEMENT);
673 if (its.first != its.second) {
674 statements = (its.first)->second;
675 for (auto it = std::next(its.first); it != its.second; ++it) {
676 statements += ", " + it->second;
677 }
678 hint += std::string(" - the statement")
679 + (std::distance(its.first, its.second) > 1 ? "s " : " ") + statements + "\n";
680 }
681 }
682
683 hint += "but it's not present!";
684 return hint;
685}
Inform * gmsg
Definition changes.cpp:7
elements
Definition IndexMap.cpp:168
Inform * gmsg
Definition changes.cpp:7
static std::multimap< OwnerType, std::string > getOwner(const std::string &att)
A representation of an Object attribute.
Definition Attribute.h:52
Compound statement.
If statement.
Definition IfStatement.h:34
The base class for all OPAL objects.
Definition Object.h:45
virtual bool shouldTrace() const =0
Trace flag.
virtual Object * makeTemplate(const std::string &, TokenStream &, Statement &)
Macro handler function.
Definition Object.cpp:71
virtual Object * clone(const std::string &name)=0
Return a clone.
virtual Object * makeInstance(const std::string &name, Statement &, const Parser *)
Macro handler function.
Definition Object.cpp:76
virtual void setShared(bool)
Set/reset shared flag.
Definition Object.cpp:247
virtual Attribute * findAttribute(const std::string &name)
Find an attribute by name.
Definition Object.cpp:56
virtual bool shouldUpdate() const =0
Update flag.
bool isTreeMember(const Object *subTree) const
Test for tree membership.
Definition Object.cpp:271
virtual void parse(Statement &)
Parse the object.
Definition Object.cpp:82
void makeDirty(Object *object)
Invalidate expressions.
Definition OpalData.cpp:481
void update()
Update all objects.
Definition OpalData.cpp:587
Object * find(const std::string &name)
Find entry.
Definition OpalData.cpp:477
static OpalData * getInstance()
Definition OpalData.cpp:193
void define(Object *newObject)
Define a new object.
Definition OpalData.cpp:400
virtual const std::string & what() const
Return the message string for the exception.
virtual const std::string & where() const
Return the name of the method or function which detected the exception.
bool stopFlag
Definition OpalParser.h:111
virtual void parseAssign(Statement &) const
Parse assignment statement.
static Token readToken()
Return next input token.
static void parseTokenList(Statement &)
static std::vector< std::shared_ptr< TokenStream > > inputStack
Definition OpalParser.h:114
virtual void parseEnd(Statement &) const
Check for end of statement.
virtual void run() const
Read current stream.
virtual Object * find(const std::string &) const
Find object by name in the main directory.
virtual void parseMacro(const std::string &name, Statement &) const
Parse macro definition or call.
static void parseBracketList(char close, Statement &)
virtual Statement * readStatement(TokenStream *) const
Read complete statement from a token stream.
virtual void printHelp(const std::string &) const
Print help on named command.
void execute(Object *, const std::string &) const
Execute or check the current command.
static std::string getHint(const std::string &, const std::string &="attribute")
virtual void parse(Statement &) const
Parse and execute current statement.
void stop() const
Set stop flag.
virtual ~OpalParser()
virtual void parseDefine(Statement &) const
Parse definition.
virtual void parseAction(Statement &) const
Parse executable command.
Parse exception.
Definition ParseError.h:31
A simple input statement in token form.
Interface for statements.
Definition Statement.h:37
Token & getCurrent()
Return current token and skip it.
Definition Statement.cpp:61
void append(const Token &)
Append a token.
Definition Statement.cpp:39
unsigned int position() const
Return current character number in line.
void restore()
Return to marked position.
bool keyword(const char *s)
Test for keyword.
virtual void execute(const Parser &)=0
Execute.
void mark()
Mark position in command.
virtual void print(std::ostream &os) const
Print statement.
bool atEnd() const
Test for end of command.
Definition Statement.cpp:41
bool delimiter(char c)
Test for delimiter.
Definition Statement.cpp:83
void start()
Return to start.
Abstract interface for a stream of input tokens.
Definition TokenStream.h:30
virtual Token readToken()=0
Read single token from stream.
Representation of a single input token.
Definition Token.h:32
bool isString() const
Test for string.
Definition Token.cpp:99
bool isDel(char del) const
Test for delimiter.
Definition Token.cpp:81
bool isWord() const
Test for word.
Definition Token.cpp:97
bool isEOF() const
Test for end of file.
Definition Token.cpp:89
const std::string & getLex() const
Return the lexeme.
Definition Token.cpp:156
bool isKey(const char *key) const
Test for keyword.
Definition Token.cpp:101
int getLine() const
Return the token's line number.
Definition Token.cpp:162
@ IS_EOF
Definition Token.h:35
const std::string & getFile() const
Return the token's file name.
Definition Token.cpp:160
While statement.
Representation objects and parsers for attribute expressions.
std::string parseString(Statement &, const char msg[])
Parse string value.
void parseDelimiter(Statement &stat, char delim)
Test for one-character delimiter.
double parseRealConst(Statement &)
Parse real constant.
bool mtrace
Trace flag.
Definition Options.cpp:31