You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
692 lines
21 KiB
692 lines
21 KiB
//==============================================================================
|
|
//
|
|
// Copyright (c) 2015-
|
|
// Authors:
|
|
// * Joachim Klein <klein@tcs.inf.tu-dresden.de>
|
|
// * David Mueller <david.mueller@tcs.inf.tu-dresden.de>
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// This file is part of the cpphoafparser library,
|
|
// http://automata.tools/hoa/cpphoafparser/
|
|
//
|
|
// The cpphoafparser library is free software; 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; either
|
|
// version 2.1 of the License, or (at your option) any later version.
|
|
//
|
|
// The cpphoafparser library 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.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
//
|
|
//==============================================================================
|
|
|
|
#ifndef CPPHOAFPARSER_HOAPARSER_H
|
|
#define CPPHOAFPARSER_HOAPARSER_H
|
|
|
|
#include <set>
|
|
#include <string>
|
|
#include <sstream>
|
|
|
|
#include "cpphoafparser/parser/hoa_lexer.hh"
|
|
#include "cpphoafparser/consumer/hoa_consumer.hh"
|
|
#include "cpphoafparser/consumer/hoa_intermediate_check_validity.hh"
|
|
#include "cpphoafparser/consumer/hoa_intermediate_resolve_aliases.hh"
|
|
#include "cpphoafparser/parser/hoa_parser_exception.hh"
|
|
|
|
|
|
/** @mainpage cpphoafparser API documentation
|
|
*
|
|
* API documentation for the <a href="http://automata.tools/hoa/cpphoafparser/">cpphoafparser</a> library.
|
|
*/
|
|
|
|
/** @namespace cpphoafparser
|
|
* The `cpphoafparser` namespace contains all the classes of the
|
|
* cpphoafparser library.
|
|
*/
|
|
namespace cpphoafparser {
|
|
|
|
/**
|
|
* Parser class for parsing HOA files.
|
|
*
|
|
* Provides a static function for parsing a HOA automaton from an input stream,
|
|
* calling into a HOAConsumer for every syntax element encountered during the parse.
|
|
*
|
|
* The parser is implemented as a simple, hand-written recursive-descent parser,
|
|
* with functions corresponding to grammar rules.
|
|
**/
|
|
class HOAParser {
|
|
public:
|
|
|
|
/**
|
|
* Function for parsing a single HOA automaton.
|
|
*
|
|
* On error, will throw HOAParserException, the consumers will generally throw
|
|
* HOAConsumerException.
|
|
*
|
|
* @param in std::istream from which the automaton will be read
|
|
* @param consumer a shared_ptr to the HOAConsumer whose functions will
|
|
* be called for each element of the HOA automaton
|
|
* @param check_validity Should the validity of the HOA be checked?
|
|
* These are checks beyond the basic syntactic well-formedness guaranteed by the grammar.
|
|
**/
|
|
static void parse(std::istream& in, HOAConsumer::ptr consumer, bool check_validity=true) {
|
|
if (consumer->parserResolvesAliases()) {
|
|
consumer.reset(new HOAIntermediateResolveAliases(consumer));
|
|
}
|
|
|
|
if (check_validity) {
|
|
consumer.reset(new HOAIntermediateCheckValidity(consumer));
|
|
}
|
|
|
|
HOAParser parser(in, consumer);
|
|
parser.nextToken();
|
|
parser.Automaton();
|
|
}
|
|
|
|
private:
|
|
/** The registered consumer */
|
|
HOAConsumer::ptr consumer;
|
|
/** The lexer for tokenizing the input stream */
|
|
HOALexer lexer;
|
|
|
|
/** The current token */
|
|
HOALexer::Token token;
|
|
/** true if we are currently in a State: definition */
|
|
bool inState;
|
|
/** the index of the current state*/
|
|
unsigned int currentState;
|
|
/** true if the current state has state labeling */
|
|
bool currentStateHasStateLabel;
|
|
|
|
|
|
/** Private constructor. */
|
|
HOAParser(std::istream& in, HOAConsumer::ptr consumer) :
|
|
consumer(consumer), lexer(in), inState(false), currentState(0), currentStateHasStateLabel(false) {
|
|
}
|
|
|
|
/** Advance to the next token. Handles TOKEN_ABORT */
|
|
void nextToken() {
|
|
token = lexer.nextToken();
|
|
if (token.kind == HOALexer::TOKEN_ABORT) {
|
|
consumer->notifyAbort();
|
|
throw "aborted";
|
|
}
|
|
}
|
|
|
|
/** Advances to the next token if it is of the expected kind, otherwise throw an error. */
|
|
void expect(HOALexer::TokenType kind, const std::string& context="") {
|
|
if (token.kind != kind) {
|
|
throw error(HOALexer::Token::forErrorMessage(kind), context);
|
|
}
|
|
|
|
// eat token
|
|
nextToken();
|
|
}
|
|
|
|
/**
|
|
* Constructs a HOAParserExeption for a syntax error.
|
|
* @param expectedTokenTypes a string detailing which token types were expected
|
|
* @param context optionally, some context for the error message */
|
|
HOAParserException error(const std::string& expectedTokenTypes, const std::string& context="") {
|
|
std::stringstream ss;
|
|
ss << "Syntax error";
|
|
if (context != "") {
|
|
ss << " (while reading " << context << ")";
|
|
}
|
|
ss << ": Expected " << expectedTokenTypes;
|
|
ss << ", got " << HOALexer::Token::forErrorMessage(token);
|
|
ss << " (line " << std::to_string(token.line) << ", col " << std::to_string(token.col) << ")";
|
|
|
|
return HOAParserException(ss.str(), token.line, token.col);
|
|
}
|
|
|
|
/** Grammar rule for the whole Automaton */
|
|
void Automaton() {
|
|
Header();
|
|
expect(HOALexer::TOKEN_BODY);
|
|
consumer->notifyBodyStart();
|
|
Body();
|
|
expect(HOALexer::TOKEN_END);
|
|
if (inState) {
|
|
consumer->notifyEndOfState(currentState);
|
|
}
|
|
consumer->notifyEnd();
|
|
}
|
|
|
|
/** Grammar rule for the HOA header */
|
|
void Header() {
|
|
Format();
|
|
HeaderItems();
|
|
}
|
|
|
|
/** Grammar rule for the HOA: header */
|
|
void Format() {
|
|
expect(HOALexer::TOKEN_HOA);
|
|
std::string version = Identifier("version");
|
|
// TODO: check format version
|
|
consumer->notifyHeaderStart(version);
|
|
}
|
|
|
|
/** Grammar rule for the remaining header items, returns if there are not more headers */
|
|
void HeaderItems() {
|
|
while (true) {
|
|
switch (token.kind) {
|
|
case HOALexer::TOKEN_STATES: HeaderItemStates(); break;
|
|
case HOALexer::TOKEN_START: HeaderItemStart(); break;
|
|
case HOALexer::TOKEN_AP: HeaderItemAP(); break;
|
|
case HOALexer::TOKEN_ALIAS: HeaderItemAlias(); break;
|
|
case HOALexer::TOKEN_ACCEPTANCE: HeaderItemAcceptance(); break;
|
|
case HOALexer::TOKEN_ACCNAME: HeaderItemAccName(); break;
|
|
case HOALexer::TOKEN_TOOL: HeaderItemTool(); break;
|
|
case HOALexer::TOKEN_NAME: HeaderItemName(); break;
|
|
case HOALexer::TOKEN_PROPERTIES: HeaderItemProperties(); break;
|
|
case HOALexer::TOKEN_HEADER_NAME: HeaderMiscItem(); break;
|
|
default:
|
|
// not a header, return
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Grammar rule for the States-header */
|
|
void HeaderItemStates() {
|
|
expect(HOALexer::TOKEN_STATES);
|
|
|
|
unsigned int states = Integer("number of states in States-header");
|
|
consumer->setNumberOfStates(states);
|
|
}
|
|
|
|
/** Grammar rule for the Start-header */
|
|
void HeaderItemStart() {
|
|
expect(HOALexer::TOKEN_START);
|
|
|
|
std::vector<unsigned int> stateConjunction;
|
|
unsigned int state = Integer("Start: index of start state");
|
|
stateConjunction.push_back(state);
|
|
while (token.kind == HOALexer::TOKEN_AND) {
|
|
expect(HOALexer::TOKEN_AND);
|
|
state = Integer("Start: index of start state in conjunction");
|
|
stateConjunction.push_back(state);
|
|
}
|
|
|
|
consumer->addStartStates(stateConjunction);
|
|
}
|
|
|
|
/** Grammar rule for the AP-header */
|
|
void HeaderItemAP() {
|
|
expect(HOALexer::TOKEN_AP);
|
|
|
|
unsigned int apCount = Integer("AP: number of atomic propositions");
|
|
|
|
std::vector<std::string> apList;
|
|
std::set<std::string> aps;
|
|
|
|
while (token.kind == HOALexer::TOKEN_STRING) {
|
|
std::string ap = QuotedString();
|
|
if (aps.find(ap) != aps.end()) {
|
|
throw HOAConsumerException("Atomic proposition \""+ap+"\" is a duplicate!");
|
|
}
|
|
aps.insert(ap);
|
|
apList.push_back(ap);
|
|
}
|
|
|
|
if (apList.size() != apCount) {
|
|
throw HOAConsumerException("Number of provided APs (" + std::to_string(apList.size()) + ") does not match number of APs that was specified (" + std::to_string(apCount) + ")");
|
|
}
|
|
|
|
consumer->setAPs(apList);
|
|
}
|
|
|
|
/** Grammar rule for the Alias-header */
|
|
void HeaderItemAlias() {
|
|
expect(HOALexer::TOKEN_ALIAS);
|
|
std::string aliasName = AliasName();
|
|
|
|
HOAConsumer::label_expr::ptr labelExpr = LabelExpr();
|
|
|
|
consumer->addAlias(aliasName, labelExpr);
|
|
}
|
|
|
|
/** Grammar rule for the Acceptance-header */
|
|
void HeaderItemAcceptance() {
|
|
expect(HOALexer::TOKEN_ACCEPTANCE);
|
|
unsigned int numberOfSets = Integer("Acceptance: number of acceptance sets");
|
|
|
|
HOAConsumer::acceptance_expr::ptr accExpr = AcceptanceCondition();
|
|
|
|
consumer->setAcceptanceCondition(numberOfSets, accExpr);
|
|
}
|
|
|
|
/** Grammar rule for the acc-name-header */
|
|
void HeaderItemAccName() {
|
|
expect(HOALexer::TOKEN_ACCNAME);
|
|
|
|
std::string accName = Identifier("acceptance name");
|
|
std::vector<IntOrString> extraInfo;
|
|
|
|
while (true) {
|
|
if (token.kind == HOALexer::TOKEN_IDENT) {
|
|
extraInfo.push_back(IntOrString(Identifier()));
|
|
} else if (token.kind == HOALexer::TOKEN_INT) {
|
|
extraInfo.push_back(IntOrString(Integer()));
|
|
} else if (token.kind == HOALexer::TOKEN_TRUE) {
|
|
extraInfo.push_back(IntOrString("t"));
|
|
expect(HOALexer::TOKEN_TRUE); // munch
|
|
} else if (token.kind == HOALexer::TOKEN_FALSE) {
|
|
extraInfo.push_back(IntOrString("f"));
|
|
expect(HOALexer::TOKEN_FALSE); // munch
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
// TODO
|
|
// if (settings == null || !settings.getFlagIgnoreAccName()) {
|
|
// consumer.provideAcceptanceName(accName, extraInfo);
|
|
//}
|
|
}
|
|
|
|
consumer->provideAcceptanceName(accName, extraInfo);
|
|
}
|
|
|
|
/** Grammar rule for the tool-header */
|
|
void HeaderItemTool() {
|
|
expect(HOALexer::TOKEN_TOOL);
|
|
|
|
std::string tool = QuotedString();
|
|
std::shared_ptr<std::string> version;
|
|
|
|
if (token.kind == HOALexer::TOKEN_STRING) {
|
|
version.reset(new std::string(QuotedString()));
|
|
}
|
|
|
|
consumer->setTool(tool, version);
|
|
}
|
|
|
|
/** Grammar rule for the name-header */
|
|
void HeaderItemName() {
|
|
expect(HOALexer::TOKEN_NAME);
|
|
|
|
std::string name = QuotedString();
|
|
|
|
consumer->setName(name);
|
|
}
|
|
|
|
/** Grammar rule for the properties-header */
|
|
void HeaderItemProperties() {
|
|
expect(HOALexer::TOKEN_PROPERTIES);
|
|
|
|
std::vector<std::string> properties;
|
|
while (true) {
|
|
if (token.kind == HOALexer::TOKEN_IDENT) {
|
|
std::string property = Identifier();
|
|
properties.push_back(property);
|
|
} else if (token.kind == HOALexer::TOKEN_TRUE) {
|
|
// t does not have the special boolean meaning here, back to string
|
|
properties.push_back("t");
|
|
expect(HOALexer::TOKEN_TRUE); // eat
|
|
} else if (token.kind == HOALexer::TOKEN_FALSE) {
|
|
// f does not have the special boolean meaning here, back to string
|
|
properties.push_back("f");
|
|
expect(HOALexer::TOKEN_FALSE); // eat
|
|
} else {
|
|
// no more properties...
|
|
break;
|
|
}
|
|
}
|
|
|
|
consumer->addProperties(properties);
|
|
}
|
|
|
|
/** Grammar rule for a misc header (not known from the format specification) */
|
|
void HeaderMiscItem() {
|
|
std::string headerName = token.vString;
|
|
headerName = headerName.substr(0, headerName.length()-1);
|
|
expect(HOALexer::TOKEN_HEADER_NAME);
|
|
|
|
std::vector<IntOrString> content;
|
|
|
|
while (true) {
|
|
if (token.kind == HOALexer::TOKEN_INT) {
|
|
content.push_back(Integer());
|
|
} else if (token.kind == HOALexer::TOKEN_IDENT) {
|
|
content.push_back(Identifier());
|
|
} else if (token.kind == HOALexer::TOKEN_STRING) {
|
|
content.push_back(IntOrString(QuotedString(), true));
|
|
} else if (token.kind == HOALexer::TOKEN_TRUE) {
|
|
// t does not have the special boolean meaning here, back to string
|
|
content.push_back(IntOrString("t", false));
|
|
expect(HOALexer::TOKEN_TRUE); // eat
|
|
} else if (token.kind == HOALexer::TOKEN_FALSE) {
|
|
// f does not have the special boolean meaning here, back to string
|
|
content.push_back(IntOrString("f", false));
|
|
expect(HOALexer::TOKEN_FALSE); // eat
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
consumer->addMiscHeader(headerName, content);
|
|
}
|
|
|
|
/** Grammar rule for the automaton body */
|
|
void Body() {
|
|
while (true) {
|
|
switch (token.kind) {
|
|
case HOALexer::TOKEN_STATE:
|
|
StateName();
|
|
break;
|
|
case HOALexer::TOKEN_END:
|
|
return;
|
|
case HOALexer::TOKEN_EOF:
|
|
return;
|
|
default:
|
|
if (inState) {
|
|
Edge();
|
|
} else {
|
|
throw error("either State: or --END--");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Grammar rule for the State definition */
|
|
void StateName() {
|
|
expect(HOALexer::TOKEN_STATE);
|
|
|
|
HOAConsumer::label_expr::ptr labelExpr;
|
|
std::shared_ptr<std::string> stateComment;
|
|
std::shared_ptr<HOAConsumer::int_list> accSignature;
|
|
|
|
if (token.kind == HOALexer::TOKEN_LBRACKET) {
|
|
labelExpr = Label();
|
|
}
|
|
|
|
unsigned int state = Integer(); // name of the state
|
|
if (token.kind == HOALexer::TOKEN_STRING) {
|
|
stateComment.reset(new std::string(QuotedString())); // state comment
|
|
}
|
|
|
|
if (token.kind == HOALexer::TOKEN_LCURLY) {
|
|
accSignature = AcceptanceSignature();
|
|
}
|
|
|
|
if (inState) {
|
|
consumer->notifyEndOfState(currentState);
|
|
}
|
|
|
|
consumer->addState(state, stateComment, labelExpr, accSignature);
|
|
|
|
// store global information:
|
|
inState = true;
|
|
currentState = state;
|
|
currentStateHasStateLabel = (bool)(labelExpr);
|
|
}
|
|
|
|
/** Grammar rule for an automaton edge */
|
|
void Edge() {
|
|
HOAConsumer::label_expr::ptr labelExpr;
|
|
std::shared_ptr<HOAConsumer::int_list> conjStates;
|
|
std::shared_ptr<HOAConsumer::int_list> accSignature;
|
|
|
|
if (token.kind == HOALexer::TOKEN_LBRACKET) {
|
|
labelExpr = Label();
|
|
}
|
|
|
|
conjStates = StateConjunction("edge");
|
|
|
|
if (token.kind == HOALexer::TOKEN_LCURLY) {
|
|
accSignature = AcceptanceSignature();
|
|
}
|
|
|
|
if (labelExpr || currentStateHasStateLabel) {
|
|
consumer->addEdgeWithLabel(currentState, labelExpr, *conjStates, accSignature);
|
|
} else {
|
|
consumer->addEdgeImplicit(currentState, *conjStates, accSignature);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Grammar rule for a state conjunction
|
|
* @param context contextual information for error messages
|
|
*/
|
|
std::shared_ptr<HOAConsumer::int_list> StateConjunction(const std::string& context) {
|
|
std::shared_ptr<HOAConsumer::int_list> stateConjunction (new HOAConsumer::int_list());
|
|
|
|
unsigned int state = Integer(context);
|
|
stateConjunction->push_back(state);
|
|
while (token.kind == HOALexer::TOKEN_AND) {
|
|
expect(HOALexer::TOKEN_AND);
|
|
state = Integer(context);
|
|
stateConjunction->push_back(state);
|
|
}
|
|
return stateConjunction;
|
|
}
|
|
|
|
/** Grammar rule for a [label-expr] */
|
|
HOAConsumer::label_expr::ptr Label() {
|
|
HOAConsumer::label_expr::ptr result;
|
|
expect(HOALexer::TOKEN_LBRACKET);
|
|
result = LabelExpr();
|
|
expect(HOALexer::TOKEN_RBRACKET);
|
|
return result;
|
|
}
|
|
|
|
/** Grammar rule for an acceptance signature */
|
|
std::shared_ptr<HOAConsumer::int_list> AcceptanceSignature() {
|
|
std::shared_ptr<HOAConsumer::int_list> result(new HOAConsumer::int_list());
|
|
|
|
expect(HOALexer::TOKEN_LCURLY);
|
|
while (token.kind == HOALexer::TOKEN_INT) {
|
|
unsigned int accSet = Integer();
|
|
result->push_back(accSet);
|
|
}
|
|
expect(HOALexer::TOKEN_RCURLY);
|
|
|
|
return result;
|
|
}
|
|
|
|
/** Grammar rule for an acceptance condition expression (handle disjunction)*/
|
|
HOAConsumer::acceptance_expr::ptr AcceptanceCondition() {
|
|
HOAConsumer::acceptance_expr::ptr left = AcceptanceConditionAnd();
|
|
while (token.kind == HOALexer::TOKEN_OR) {
|
|
expect(HOALexer::TOKEN_OR);
|
|
|
|
HOAConsumer::acceptance_expr::ptr right = AcceptanceConditionAnd();
|
|
left = left | right;
|
|
}
|
|
return left;
|
|
}
|
|
|
|
/** Grammar rule for conjunction in an acceptance condition */
|
|
HOAConsumer::acceptance_expr::ptr AcceptanceConditionAnd() {
|
|
HOAConsumer::acceptance_expr::ptr left = AcceptanceConditionAtom();
|
|
while (token.kind == HOALexer::TOKEN_AND) {
|
|
expect(HOALexer::TOKEN_AND);
|
|
|
|
HOAConsumer::acceptance_expr::ptr right = AcceptanceConditionAtom();
|
|
left = left & right;
|
|
}
|
|
return left;
|
|
}
|
|
|
|
/** Grammar rule for the atoms in an acceptance condition */
|
|
HOAConsumer::acceptance_expr::ptr AcceptanceConditionAtom() {
|
|
HOAConsumer::acceptance_expr::ptr result;
|
|
|
|
switch (token.kind) {
|
|
case HOALexer::TOKEN_LPARENTH:
|
|
expect(HOALexer::TOKEN_LPARENTH);
|
|
result = AcceptanceCondition();
|
|
expect(HOALexer::TOKEN_RPARENTH);
|
|
return result;
|
|
case HOALexer::TOKEN_TRUE:
|
|
expect(HOALexer::TOKEN_TRUE);
|
|
result.reset(new HOAConsumer::acceptance_expr(true));
|
|
return result;
|
|
case HOALexer::TOKEN_FALSE:
|
|
expect(HOALexer::TOKEN_FALSE);
|
|
result.reset(new HOAConsumer::acceptance_expr(false));
|
|
return result;
|
|
case HOALexer::TOKEN_IDENT:
|
|
result.reset(new HOAConsumer::acceptance_expr(AcceptanceConditionTemporalOperator()));
|
|
return result;
|
|
default:
|
|
throw error("acceptance condition");
|
|
}
|
|
}
|
|
|
|
/** Grammar rule for a temporal operator (Fin/Inf) in an acceptance condition */
|
|
AtomAcceptance::ptr AcceptanceConditionTemporalOperator() {
|
|
AtomAcceptance::AtomType atomType = AtomAcceptance::TEMPORAL_FIN;
|
|
bool negated = false;
|
|
unsigned int accSetIndex;
|
|
|
|
std::string temporalOperator = Identifier();
|
|
|
|
if (temporalOperator == "Fin") {
|
|
atomType = AtomAcceptance::TEMPORAL_FIN;
|
|
} else if (temporalOperator == "Inf") {
|
|
atomType = AtomAcceptance::TEMPORAL_INF;
|
|
} else {
|
|
throw error("either 'Fin' or 'Inf'", "acceptance condition");
|
|
}
|
|
|
|
expect(HOALexer::TOKEN_LPARENTH, "acceptance condition");
|
|
if (token.kind == HOALexer::TOKEN_NOT) {
|
|
expect(HOALexer::TOKEN_NOT);
|
|
negated = true;
|
|
}
|
|
accSetIndex = Integer("acceptance set index");
|
|
expect(HOALexer::TOKEN_RPARENTH, "acceptance condition");
|
|
|
|
return AtomAcceptance::ptr(new AtomAcceptance(atomType, accSetIndex, negated));
|
|
}
|
|
|
|
/** Grammar rule for a label expression (handle disjunction) */
|
|
HOAConsumer::label_expr::ptr LabelExpr() {
|
|
HOAConsumer::label_expr::ptr left = LabelExprAnd();
|
|
while (token.kind == HOALexer::TOKEN_OR) {
|
|
expect(HOALexer::TOKEN_OR);
|
|
|
|
HOAConsumer::label_expr::ptr right = LabelExprAnd();
|
|
left = left | right;
|
|
}
|
|
return left;
|
|
}
|
|
|
|
/** Grammar rule for a label expression (handle conjunction) */
|
|
HOAConsumer::label_expr::ptr LabelExprAnd() {
|
|
HOAConsumer::label_expr::ptr left = LabelExprAtom();
|
|
while (token.kind == HOALexer::TOKEN_AND) {
|
|
expect(HOALexer::TOKEN_AND);
|
|
|
|
HOAConsumer::label_expr::ptr right = LabelExprAtom();
|
|
left = left & right;
|
|
}
|
|
return left;
|
|
}
|
|
|
|
/** Grammar rule for a label expression (handle atoms) */
|
|
HOAConsumer::label_expr::ptr LabelExprAtom() {
|
|
HOAConsumer::label_expr::ptr result;
|
|
|
|
switch (token.kind) {
|
|
case HOALexer::TOKEN_LPARENTH:
|
|
expect(HOALexer::TOKEN_LPARENTH);
|
|
result = LabelExpr();
|
|
expect(HOALexer::TOKEN_RPARENTH);
|
|
return result;
|
|
case HOALexer::TOKEN_TRUE:
|
|
expect(HOALexer::TOKEN_TRUE);
|
|
result.reset(new HOAConsumer::label_expr(true));
|
|
return result;
|
|
case HOALexer::TOKEN_FALSE:
|
|
expect(HOALexer::TOKEN_FALSE);
|
|
result.reset(new HOAConsumer::label_expr(false));
|
|
return result;
|
|
case HOALexer::TOKEN_NOT:
|
|
expect(HOALexer::TOKEN_NOT);
|
|
result = LabelExprAtom();
|
|
return !result;
|
|
case HOALexer::TOKEN_INT: {
|
|
unsigned int apIndex = Integer();
|
|
result.reset(new HOAConsumer::label_expr(AtomLabel::createAPIndex(apIndex)));
|
|
return result;
|
|
}
|
|
case HOALexer::TOKEN_ALIAS_NAME: {
|
|
std::string aliasName = AliasName();
|
|
result.reset(new HOAConsumer::label_expr(AtomLabel::createAlias(aliasName)));
|
|
return result;
|
|
}
|
|
default:
|
|
throw error("label expression");
|
|
}
|
|
}
|
|
|
|
/** Grammar rule for a quoted string */
|
|
std::string QuotedString(const std::string& context="") {
|
|
if (token.kind != HOALexer::TOKEN_STRING) {
|
|
expect(HOALexer::TOKEN_STRING, context);
|
|
}
|
|
|
|
std::string result = token.vString;
|
|
// eat token
|
|
nextToken();
|
|
|
|
result = HOAParserHelper::unquote(result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/** Grammar rule for a HOA identifier */
|
|
std::string Identifier(const std::string& context="") {
|
|
if (token.kind != HOALexer::TOKEN_IDENT) {
|
|
expect(HOALexer::TOKEN_IDENT, context);
|
|
}
|
|
|
|
std::string result = token.vString;
|
|
// eat token
|
|
nextToken();
|
|
|
|
return result;
|
|
}
|
|
|
|
/** Grammar rule for an @@alias-name. Returns the name without the leading @@. */
|
|
std::string AliasName() {
|
|
if (token.kind != HOALexer::TOKEN_ALIAS_NAME) {
|
|
expect(HOALexer::TOKEN_ALIAS_NAME);
|
|
}
|
|
|
|
std::string result = token.vString;
|
|
// eat token
|
|
nextToken();
|
|
|
|
// eat @
|
|
result = result.substr(1);
|
|
|
|
return result;
|
|
}
|
|
|
|
/** Grammar rule for an unsigned integer */
|
|
unsigned int Integer(const std::string& context="") {
|
|
if (token.kind != HOALexer::TOKEN_INT) {
|
|
expect(HOALexer::TOKEN_INT, context);
|
|
}
|
|
|
|
unsigned int result = token.vInteger;
|
|
// eat token
|
|
nextToken();
|
|
|
|
return result;
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|