Re: x3: Parsing with lexer tokens

Mikael Asplund <[email protected]>
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
Hi!

I finally managed to get a working example code of parsing with tokens, thanks to Mr Guzman! Very much obliged!
I thought I'd share it so it's available for the next person with the same problem. The debug-outputter object has some code that at least currently doesn't seem to work with GCC (works with clang) that I had to comment out, and visual studio will not let me have a semantic action attached at all in the example (visual studio 2015 update 1), but that's likely to improve...

So here is the working example:

http://coliru.stacked-crooked.com/a/94ab3dae700b9049

Regards,
   Mikael

From: Mikael Asplund [mailto:[email protected]]
Sent: Tuesday, February 16, 2016 16:41
To: [email protected]
Subject: [Spirit-general] x3: Parsing with lexer tokens

Hi!

I'm trying to use spirit x3 to parse output from my lexer (needed), which is a vector of tokens. I'm running into all sorts of compiler errors, though, and there are no examples out there that I could find, so I wrote a minimal example and put it online to request comments from you on how to proceed.

Please have a look here:  http://coliru.stacked-crooked.com/a/8975361b37f0c640

This little example is supposed to be run like this: ./a.out  1  +  3

Any help?

  /Mikael

PS. I'll include the code here too, but it's probably more readable in the link above. Here we go:


#include <string>
#include <vector>
#include <cctype>
#include <iostream>

#include <boost/spirit/home/x3.hpp>

using std::string;
using std::vector;
namespace x3 = boost::spirit::x3;

int parse_input(vector<string> v);

int main(int argc, const char* argv[]) {
  if (argc > 1) {
    return parse_input(vector<string>(&argv[1], &argv[argc + !argc]));
  }
  return -1;
}

namespace lexer {
                struct SourcePosition {
                                string file;
                                int line = -1;
                };

                enum class TokenType { OPERATOR, NUMBER, IDENTIFIER };

                struct Token : public SourcePosition {
                                Token(TokenType t, const string& s, const SourcePosition& pos = SourcePosition())
                                : SourcePosition(pos), type(t), str(s) {}

                                TokenType type;
                                string str;

                                bool operator == (const Token& o) { // Token with empty string will match any token of that type
                                                return type == o.type && (str == o.str || str.empty() || o.str.empty());
                                }
                };

                std::ostream& operator<<(std::ostream& o, const TokenType& t) {
                                return o << (t == TokenType::OPERATOR ? "OPERATOR" :
                                                                                t == TokenType::NUMBER ? "NUMBER" : "IDENTIFIER");
                }
                std::ostream& operator<<(std::ostream& o, const Token& t) {
                                return o << t.type << "(\"" << t.str << "\")";
                }

                vector<Token> lex(vector<string> v) {
                                vector<Token> out;
                                auto conforms_to = [](string s, auto pred) {
                                                return s.end() != std::find_if(s.begin(), s.end(), pred);
                                };
                                for (auto& s : v) {
                                                if (conforms_to(s, [](char c){ return std::isdigit(c); })) {
                                                                out.push_back(Token(TokenType::NUMBER, s));
                                                } else if (conforms_to(s, [](char c){ return std::isalnum(c); })) {
                                                                out.push_back(Token(TokenType::IDENTIFIER, s));
                                                } else {
                                                                out.push_back(Token(TokenType::OPERATOR, s));
                                                }
                                }
                                return out;
                }
}

namespace parser {
                using lexer::Token;
                using lexer::TokenType;

                struct TokenLiteralParser : x3::parser<TokenLiteralParser> {
                                TokenLiteralParser(const Token& iTok) : tok(iTok) {}

                                template <typename It, typename Ctx, typename A>
                                bool parse(It& first, const It& last, const Ctx& ctx, x3::unused_type, A& attr) const {
                                                if (first != last && *first == tok) {
                                                                ++first;
                                                                return true;
                                                }
                                                return false;
                                }

                                Token tok;
                };

    Token TokenAnyNumber(TokenType::NUMBER, "");
    Token TokenAnyIdentifier(TokenType::IDENTIFIER, "");
    Token TokenPlus(TokenType::OPERATOR, "+");
    Token TokenMinus(TokenType::OPERATOR, "-");


}

struct Outputter {
                template <typename T>
                Outputter& operator=(const T& t) {
                                std::cout << "output => " << typeid(t).name() << ": " << t << std::endl;
                                return *this;
                }
} outputter;

int parse_input(vector<string> v) {
                using namespace parser;

                using TL = TokenLiteralParser;

                auto lexed = lexer::lex(v);
                std::copy(lexed.begin(), lexed.end(), std::ostream_iterator<Token>(std::cout << "\n------ TOKENS ------\n", "\n"));
                std::cout << "--------------------\n";

                auto first = lexed.begin();
                auto last = lexed.end();

                Outputter out;

                bool r = phrase_parse(first, last,

            //  Begin grammar
            (
                (TL(TokenAnyNumber) % (TL(TokenPlus) | TL(TokenMinus)))
            ),
            //  End grammar

            x3::unused, out);

                return !r;
}

------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140

_______________________________________________
Spirit-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spirit-general
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.