简体   繁体   中英

Why I am getting bad output in this flex file?

I am trying to write a Flex file that allows to read systemctl output. The idea is to show only those service that have failed to start. My code is:

%{
    #include <iostream>
    #include <fstream>

    using namespace std;

    ifstream file;
    char* service_name;
    int nfs=0;
%}

failed_service      *failed*
                     
%%
                                                           
failed_service          {nfs++;cout << yytext << endl;}  
  
%%


int main()
{   
    
    system("systemctl > /var/tmp/system_start.txt");
    file.open("/var/tmp/system_start.txt");
    
    yyFlexLexer strm (&file,0);   
    strm.yylex();
}

Can you tell me where I am failing? The output show me the entire systemctl output Thanks.

Flex is probably not the best tool for this task. I'd suggest the grep command-line utility.

Flex is a tool used in writing parsers; its goal is to split the input into a sequence of tokens . It never searches for a pattern. At each input point, it tries all the configured patterns to find a match starting at that point, and selects the longest possibility. It then executes the associated action, and then continues after advancing to the first character following the match.

If it any point it fails to match the current input character, it uses a default rule whose pattern matches any single character, and whose action is to print the character. Since your only rule never matches, the entire input is copied to the output one character at a time using this default rule.

It is not in any way line oriented. You can split the input into lines by using an explicit pattern, but none of that happens automatically.

If you are going to use flex, you'll want to learn at least a little bit about regular expressions . *failed* is not a valid regular expression; in a regular expression, the * operator means zero or more repetitions of the thing it follows, so it cannot appear at the beginning of a pattern. (The second * in *failed* is valid but means "zero or more d s", which is not what you meant. You might be confusing regular expressions with shell pathname expansion ("globbing") in which a * means "zero or more characters other than / ".

In any case, *failed* is not the pattern you are matching in that flex file. The pattern is failed_service , which is a valid regular expression, which matches itself. You previously defined the rather unnecessary macro failed_service , but the flex syntax for expanding macros is {macro-name} . Had you managed to expand that macro, flex would have reported an invalid pattern. However, there is no need for macros in a flex file; you can simply place the pattern itself in the rule.

There is a brief description of the syntax of regular expressions accepted by flex in the flex manual , but it assumes some basic familiarity with the concepts. The manual also explains the flex file format and the matching algorithm.

Nonetheless, I really think you'd be better off just piping the output of systemctl through grep ( systemctl | grep -Fw failed , for example). Grep , which is line oriented, is highly optimised for tasks like this, and does not require you to come up with a set of patterns which cover all possibilities.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM