提升精神渴望 [英] Boost Spirit Qi Expectation

查看:210
本文介绍了提升精神渴望的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



例如,我想解析:

  Func Ident {
Mov name,hello
Push 5
Exit
}

到目前为止,还不错。我可以正确解析。
然而,错误处理程序有时会出现奇怪的错误位置。以下面的错误代码为例:

  Func Ident {
Mov namehello; < - comma is missing here
Push 5
Exit
}

以下是此解析中涉及的规则:

  gr_function = lexeme [Func> !(alnum |'_')] //确保整个单词
> gr_identifier
> {
> *(gr_instruction
| gr_label
| gr_vardecl
| gr_paramdecl)
> };

gr_instruction = gr_instruction_names
> gr_operands;

gr_operands = - (gr_operand%',');

解析将注意到错误,但抱怨在Mov之后缺少}。
我有一个感觉,问题是在Func的定义,但不能确定。
我想解析器抱怨一个缺少的,
如果它抱怨随之而来的错误,这将是确定的,但它应该确定一个缺少的逗号作为

  gr_operands = - (gr_operand 
>> *(','
> gr_operand)
);

和其他人,但出现其他奇怪的错误。



有没有人知道如何说好吧,你可能有一个没有操作数的指令,但如果你找到一个,下一个之前没有逗号,在逗号上失败?



UPDATE



感谢您的回答。 gr_operand的定义如下:

  gr_operand =(gr_operand_intlit 
| gr_operand_flplit
| gr_operand_strlit
| gr_operand_register
| gr_operand_identifier);

gr_operand_intlit = int_;

gr_operand_flplit = double_;

gr_operand_strlit =''
> strlitcont
>''
;

gr_operand_register = gr_register_names;

// TODO:也必须不接受语句中的关键字语法
gr_operand_identifier =!(gr_instruction_names | gr_register_names)
>> raw [
lexeme [(alpha |'_')>> *(alnum |'_')]
];

escchar.name(\\\);
escchar ='\\'>> char _(\);

strlitcont.name(String literal content);
strlitcont = *(escchar |〜char_(''));


  

你可能想明确一个操作数, gr_operand = gr_identifier | gr_string;
gr_string = lexeme [''>> *(\\|〜char _(\))>>''];

不相关,但您可能希望明确一个换行符开始一个新语句(使用blank_type船长):

 >> {
>> - (
gr_instruction
| gr_label
| gr_vardecl
| gr_paramdecl
)%eol
> };

现在,解析器将能够抱怨在解析失败时期望换行符。



我在原始帖子中使用您的草图创建了一个完整的示例。



查看 在Coliru上

  #define BOOST_SPIRIT_DEBUG 
#include< boost / spirit / include / qi.hpp>

命名空间qi = boost :: spirit :: qi;

template< typename It,typename Skipper = qi :: blank_type>
struct parser:qi :: grammar< It,Skipper>
{
parser():parser :: base_type(start)
{
使用命名空间qi;

start = lexeme [Func>> !(alnum |'_')]>功能;
function = gr_identifier
>> {
>> - (
gr_instruction
// | gr_label
// | gr_vardecl
// | gr_paramdecl
)%eol
> };

gr_instruction_names.add(Mov,unused);
gr_instruction_names.add(Push,unused);
gr_instruction_names.add(Exit,unused);

gr_instruction = lexeme [gr_instruction_names>> !(alnum |_)]> gr_operands;
gr_operands = - (gr_operand%',');

gr_identifier = lexeme [>> *(alnum |'_')];
gr_operand = gr_identifier | gr_string;
gr_string = lexeme [''>> *(\\|〜char _(\))> '''];

BOOST_SPIRIT_DEBUG_NODES((start)(function)(gr_intstruction)(gr_operands)(gr_identifier)(gr_operand)(gr_string));
}
$ b b private:
qi :: symbols< char,qi :: unused_type> gr_instruction_names;
qi :: rule< It,Skipper> start,function,gr_instruction,gr_operands,gr_identifier,gr_operand,gr_string;
};

int main()
{
typedef boost :: spirit :: istream_iterator It;
std :: cin.unsetf(std :: ios :: skipws);
It f(std :: cin),l;

parser< It,qi :: blank_type> p;

try
{
bool ok = qi :: phrase_parse(f,l,p,qi :: blank);
if(ok)std :: cout<<parse success \\\
;
else std :: cerr<<parse failed:'<< std :: string(f,l)<<'\\\
;

if(f!= l)std :: cerr<<trailing unparsed:'<< std :: string(f,l)<<'\\\
;
return ok;
} catch(const qi :: expectation_failure< It> e)
{
std :: string frag(e.first,e.last);
std :: cerr<< e.what()< '< frag< '\\\
;
}

return false;
}


I am relatively new to Spirit Qi, and am trying to parse an assembler-like language.

For example, I'd like to parse:

Func Ident{
    Mov name, "hello"
    Push 5
    Exit
}

So far, so good. I can parse it properly. However, the error handler sometimes comes up with strange error locations. Take for example the following faulty code:

Func Ident{
    Mov name "hello" ; <-- comma is missing here
    Push 5
    Exit
}

Here are the rules involved in this parsing:

    gr_function = lexeme["Func" >> !(alnum | '_')] // Ensure whole words
                    > gr_identifier
                    > "{"
                    > *( gr_instruction
                            |gr_label
                        |gr_vardecl
                        |gr_paramdecl)
                    > "}";

    gr_instruction = gr_instruction_names
                     > gr_operands;

    gr_operands = -(gr_operand % ',');

The parse will notice the error, but complain about a missing "}" after the Mov. I have a feeling that the issue is in the definition for "Func", but cannot pinpoint it. I'd like the parser to complain about a missing "," It would be ok if it complained about consequential errors, but it should definitely pinpoint a missing comma as the culprit.

I have tried variations such as:

gr_operands = -(gr_operand 
                >> *(','
                     > gr_operand)
                );

And others, but with other strange errors.

Does anyone have an idea of how to say "Ok, you may have an instruction without operands, but if you find one, and there is no comma before the next, fail at the comma"?

UPDATE

Thank you for your answers so far. The gr_operand is defined as follows:

    gr_operand = ( gr_operand_intlit
                  |gr_operand_flplit
                  |gr_operand_strlit
                  |gr_operand_register
                  |gr_operand_identifier);

    gr_operand_intlit = int_;

    gr_operand_flplit = double_;

    gr_operand_strlit = '"'
                        > strlitcont
                        > '"'
                    ;

    gr_operand_register = gr_register_names;

    // TODO: Must also not accept the keywords from the statement grammar
    gr_operand_identifier = !(gr_instruction_names | gr_register_names)
                            >> raw[
                                    lexeme[(alpha | '_') >> *(alnum | '_')]
                                  ];

    escchar.name("\\\"");
    escchar     = '\\' >> char_("\"");

    strlitcont.name("String literal content");
    strlitcont  = *( escchar | ~char_('"') );

解决方案

You'll want to make it explicit what can be an operand. I guessed this:

gr_operand    = gr_identifier | gr_string;
gr_string     = lexeme [ '"' >> *("\"\"" | ~char_("\"")) >> '"' ];

Unrelated, but you might want to make it clear that a newline starts a new statement (using blank_type as the skipper):

        >> "{"
        >> -(
                  gr_instruction
                | gr_label
                | gr_vardecl
                | gr_paramdecl
            ) % eol
        > "}";

Now, the parser will be able to complain that it expects a newline at the time of parse fail.

I made up a fully working sample using your sketches in the original post.

See it live on Coliru:

#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>

namespace qi    = boost::spirit::qi;

template <typename It, typename Skipper = qi::blank_type>
    struct parser : qi::grammar<It, Skipper>
{
    parser() : parser::base_type(start)
    {
        using namespace qi;

        start = lexeme["Func" >> !(alnum | '_')] > function;
        function = gr_identifier
                    >> "{"
                    >> -(
                              gr_instruction
                            //| gr_label
                            //| gr_vardecl
                            //| gr_paramdecl
                        ) % eol
                    > "}";

        gr_instruction_names.add("Mov", unused);
        gr_instruction_names.add("Push", unused);
        gr_instruction_names.add("Exit", unused);

        gr_instruction = lexeme [ gr_instruction_names >> !(alnum|"_") ] > gr_operands;
        gr_operands = -(gr_operand % ',');

        gr_identifier = lexeme [ alpha >> *(alnum | '_') ];
        gr_operand    = gr_identifier | gr_string;
        gr_string     = lexeme [ '"' >> *("\"\"" | ~char_("\"")) >> '"' ];

        BOOST_SPIRIT_DEBUG_NODES((start)(function)(gr_instruction)(gr_operands)(gr_identifier)(gr_operand)(gr_string));
    }

  private:
    qi::symbols<char, qi::unused_type> gr_instruction_names;
    qi::rule<It, Skipper> start, function, gr_instruction, gr_operands, gr_identifier, gr_operand, gr_string;
};

int main()
{
    typedef boost::spirit::istream_iterator It;
    std::cin.unsetf(std::ios::skipws);
    It f(std::cin), l;

    parser<It, qi::blank_type> p;

    try
    {
        bool ok = qi::phrase_parse(f,l,p,qi::blank);
        if (ok)   std::cout << "parse success\n";
        else      std::cerr << "parse failed: '" << std::string(f,l) << "'\n";

        if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
        return ok;
    } catch(const qi::expectation_failure<It>& e)
    {
        std::string frag(e.first, e.last);
        std::cerr << e.what() << "'" << frag << "'\n";
    }

    return false;
}

这篇关于提升精神渴望的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆