Search code examples
c++compiler-constructionboost-spirit

PEG rule to identify function protoype


I am trying to create a parser that can parse C code. My use case to parse a buffer that may contain a function prototype. I want to push this function name into a symbol table. I am new to Spirit and PEG and I am trying to figure out how I can write a rule that can identify function prototypes.

This is my current implementation:

auto nameRule = x3::alpha >> *x3::alnum;
auto fcnPrototypeRule = nameRule >> *nameRule;
auto fcnRule = fcnPrototypeRule >> space >> x3::char_('(') >> -(nameRule % ',') >> x3::char_(');');

This is my application code:

class Parser {   

    public:
    std::string functionParser(const std::string& input) {
        std::string output;
        x3::phrase_parse(input.begin(), input.end(), fcnRule, space, output);
        return output;
    }
};

input is = "extern void myFunction();" The output is an empty string. I wanted to get the function prototype.


Solution

  • Looks like ');' should have been ");"?

    Also since you have a skipper (x3::space in the call to phrase_parse) it doesn't make much sense to:

    • also specify space in your parser expression (it will never match)
    • not wrap the nameRule inside a lexeme or noskip directive. See also Boost spirit skipper issues

    So first stab at making it work:

    std::string functionParser(const std::string& input) {
        namespace x3 = boost::spirit::x3;
    
        auto nameRule = x3::lexeme [x3::alpha >> *x3::alnum];
        auto fcnPrototypeRule = nameRule >> *nameRule;
        auto fcnRule = fcnPrototypeRule >> x3::char_('(') >> -(nameRule % ',') >> x3::char_(");");
        std::string output;
        x3::phrase_parse(input.begin(), input.end(), fcnRule, x3::space, output);
        return output;
    }
    

    However, you'll notice it returns ndn() (Live On Coliru).

    I think it's basically caused by the fact that your AS (std::string) doesn't match the grammar much. I'd say it looks likeyou mean to "match" instead of "parse" and I'd use x3::raw to expose the raw match:

    Live On Colriu

    #include <boost/spirit/home/x3.hpp>
    #include <iostream>
    #include <iomanip>
    
    std::string functionParser(const std::string& input) {
        namespace x3 = boost::spirit::x3;
    
        auto nameRule = x3::lexeme [x3::alpha >> *x3::alnum];
        auto fcnPrototypeRule = nameRule >> *nameRule;
        auto fcnRule = x3::raw[ fcnPrototypeRule >> '(' >> -(nameRule % ',') >> ')' >> ';' ];
        std::string output;
        x3::phrase_parse(input.begin(), input.end(), fcnRule, x3::space, output);
        return output;
    }
    
    int main() {
        for (auto s : {
            "extern void myFunction();",
            })
        {
            std::cout << std::quoted(s) << " -> " << std::quoted(functionParser(s)) << "\n";
        }
    }