【问题标题】:boost spirit distinct keyword does not work as expected提升精神不同的关键字不能按预期工作
【发布时间】:2017-10-26 17:31:41
【问题描述】:

这是我的小样本..我有一种语言,在解析时我有类似的东西

 foo()
 nextfoo()  <-- here an error appears because of the keyword "next" 

所以语法

 typedef boost::proto::result_of::deep_copy<BOOST_TYPEOF(ascii::no_caseqi::lit(std::wstring())])>::type nocaselit_return_type;

   nocaselit_return_type nocaselit(const std::wstring& keyword)
   {
     return boost::proto::deep_copy(ascii::no_case[qi::lit(keyword)]);
   }


keywords = nocaselit(L"next")
    | nocaselit(L"else")
    | nocaselit(L"if")
    | nocaselit(L"then")
    | nocaselit(L"for")
    | nocaselit(L"to")
    | nocaselit(L"dim")
    | nocaselit(L"true")
    | nocaselit(L"false")
    | nocaselit(L"as")
    | nocaselit(L"class")
    | nocaselit(L"end")
    | nocaselit(L"function")
    | nocaselit(L"new")
    | nocaselit(L"sub");


  name_valid =   !keywords>> lexeme[+(boost::spirit::standard_wide::alpha | '_') >> *(boost::spirit::standard_wide::alnum | '_')];

我从 docu 和 goolge 中了解到,我必须编写类似这样的内容才能使解析器正确使用关键字

 name_valid =   distinct(Keywords)[ lexeme[+(boost::spirit::standard_wide::alpha | '_') >> *(boost::spirit::standard_wide::alnum | '_')] ];

但这不起作用..有人能解释一下为什么吗?

特殊问题 .. 只要我使用上面的语法,我就会收到模板编译器错误,工作示例必须按以下方式编写(关键字列表是内联的,而不是规则)。我认为这与规则的类型规范有关。但正确的是什么?

 name_valid =   distinct(nocaselit(L"next")| nocaselit(L"else") | ... )
 [ lexeme[+(boost::spirit::standard_wide::alpha | '_') >> *(boost

谢谢

【问题讨论】:

  • 你是如何定义nocaselit的?这不是我以前见过的。
  • 将 nocaselit 放入文本中 ..

标签: boost boost-spirit


【解决方案1】:

distinct 指令将主题解析器置于[] 块内,而不是()。在 () 内指定边界禁止的排除(通常是由标识符字符组成的字符集)。

还可以考虑使用qi::symbol,它与qi::no_case 配合得很好,但在内部使用了一个Trie,从而无需任何回溯。

当我靠近计算机时,我将提供一个工作示例。同时,请随时在此处查找现有示例:How to parse reserved words correctly in boost spirit

演示

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_distinct.hpp>
namespace qi = boost::spirit::qi;
namespace qr = boost::spirit::repository::qi;
namespace enc = boost::spirit::standard_wide;

template <typename It>
struct Grammar : qi::grammar<It> {

    Grammar() : Grammar::base_type(start) {
        using namespace qi;
        auto kw = qr::distinct(copy(enc::alnum | L'_'));

        start         = skip(enc::space) [function_call];
        function_call = identifier >> L'(' >> L')';
        identifier    = !keyword >> raw[(enc::alpha|L'_') >> *(enc::alnum|L'_')];

        keyword       = kw[ no_case[keywords] ];
        BOOST_SPIRIT_DEBUG_NODES((start)(function_call)(identifier)(keyword));
    }
  private:
    qi::rule<It> start;
    qi::rule<It, enc::space_type> function_call;

    // implicit lexemes
    struct keywords_t : qi::symbols<wchar_t> {
        keywords_t() { 
            this->add
                (L"as")(L"class")(L"dim")(L"else")(L"end")(L"false")
                (L"for")(L"function")(L"if")(L"new")(L"next")(L"sub")
                (L"then")(L"to")(L"true");
        }
    } keywords;
    qi::rule<It, std::string()> identifier, keyword;
};

int main() {
    using It = std::wstring::const_iterator;
    Grammar<It> const g;

    for (std::wstring input : {
            L"foo()",
            L"nextfoo()",
        })
    {
        It f=input.begin(), l=input.end();
        if (parse(f, l, g)) {
            std::wcout << L"Parse success\n";
        } else {
            std::wcout << L"Parse failed\n";
        }

        if (f!=l) {
            std::wcout << L"Remaining unparsed input: '" << std::wstring(f,l) << L"\n";
        }
    }
}

打印

Parse success
Parse success

如预期的那样

【讨论】:

  • 添加了一个工作示例Live On Coliru
  • 您的示例有效.. 无论如何我不明白为什么我的第一个版本也带有“!关键字”不做同样的工作
  • 您使用!keywords 的第一个版本不使用distinct,而是使用(参见kw())。要理解它,understand that PEG rules are greedy,总是接受第一个匹配项(如果适用,也是最长的匹配项)。 intfoo确实匹配int(离开foo)。
猜你喜欢
  • 1970-01-01
  • 2018-05-05
  • 2011-05-17
  • 2015-06-26
  • 2013-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多