SAWYER_EXPORT std::string
Grammar::evalArgument(TokenStream &tokens, ErrorLocation &eloc, bool requireRight) const {
    std::string retval, data;
    size_t depth = 0;
    while (!tokens.atEof()) {
        if (tokens.isa(TOK_LEFT)) {
            ++depth;
            retval += tokens.lexeme();
            tokens.consume();
        } else if (tokens.isa(TOK_RIGHT)) {
            if (0 == depth)
                break;
            --depth;
            retval += tokens.lexeme();
            tokens.consume();
        } else if (tokens.isa(TOK_FUNCTION)) {
            retval += evalFunction(tokens, eloc);
        } else {
            retval += tokens.lexeme();
            tokens.consume();
        }
    }
    if (requireRight) {
        if (!tokens.isa(TOK_RIGHT))
            throw SyntaxError("end-of-argument expected");
        tokens.consume();
    }
    if (depth > 0)
        throw SyntaxError("expected end-of-argument marker");
    return retval;
}
SAWYER_EXPORT std::string
Grammar::eval(TokenStream &tokens, ErrorLocation &eloc) const {
    std::string retval;
    while (!tokens.atEof()) {
        retval += evalArgument(tokens, eloc, LEAVE);
        if (tokens.isa(TOK_RIGHT))
            throw SyntaxError("unexpected end-of-argument");
    }
    return retval;
}
SAWYER_EXPORT std::string
Grammar::readArgument(TokenStream &tokens, ErrorLocation &eloc, bool requireRight) const {
    std::string retval;
    size_t depth = 0;
    for (/*void*/; !tokens.atEof(); tokens.consume()) {
        if (tokens.isa(TOK_LEFT)) {
            ++depth;
        } else if (tokens.isa(TOK_RIGHT)) {
            if (0 == depth)
                break;
            --depth;
        }
        retval += tokens.lexeme();
    }
    if (requireRight) {
        if (!tokens.isa(TOK_RIGHT))
            throw SyntaxError("end-of-argument expected");
        tokens.consume();
    }
    if (depth > 0)
        throw SyntaxError("expected end-of-argument marker");
    return retval;
}