Contents |
Crie um analisador lexical (especificação para a ferramenta Flex) que aceite uma lista de cabeçalhos de mensagens e que indique na saída o remetente que produz mais tráfego (e o valor do tráfego em KB) e qual a hora de maior tráfego (e o valor do tráfego em KB).
Cada uma das linhas tem os seguintes campos (separados por um ou mais caracteres de tabulação):
Codifique todas as funções auxiliares. Pode utilizar estruturas de dados C++ e da STL (e.g. std::string, std::vector, std::map, etc.). Por simplicidade, considere os caracteres acentuados iguais aos não acentuados.
Exemplo de entrada:
Results are out! Lucke vader@empire.net 23:38 902 KB
Adorable kitties Mary jaba@hut.com 21:21 1000 KB
Bad Romance John Me, "Tom & Jerry" 5:08 10 KB
Telephone John everyone@list.net 9:31 201 KB
Telephone John everyone@list.net 9:34 101 KB
Re: Telephone John people@work.com 9:45 901 KB
All The Pretty Little Horses Mary cute@gmail.com 12:38 1 MB
Fwd: Adorable kitties Mary cute@gmail.com 01:21 1 MB
Saída correspondente:
Mary, 3048
9, 1203
Download this code: list-accounting.l.
%option stack 8bit noyywrap
%{
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
static std::string subject, sender, recipient;
static std::string strlit, *current;
static int hour = -1, minutes = -1;
static int size = -1, multiplier = 1;
typedef std::map<std::string, int> SIMT;
typedef std::map<int, int> IIMT;
static SIMT sizesBySender;
static IIMT sizesByHour;
inline void yyerror(const char *msg) { std::cerr << msg << std::endl; }
%}
%x X_FROM X_TO X_HOURS X_MINUTES X_SIZE X_STRING
%%
<INITIAL>\" strlit = yytext; current = &subject; yy_push_state(X_STRING);
<X_FROM>\" strlit = yytext; current = &sender; yy_push_state(X_STRING);
<X_TO>\" strlit = yytext; current = &recipient; yy_push_state(X_STRING);
<INITIAL>\t+ BEGIN(X_FROM); sender = "";
<INITIAL>. subject += *yytext;
<INITIAL>\n yyerror("newline in subject");
<X_FROM>\t+ BEGIN(X_TO); recipient = "";
<X_FROM>. sender += *yytext;
<X_FROM>\n yyerror("newline in sender");
<X_TO>\t+ BEGIN(X_HOURS);
<X_TO>. recipient += *yytext;
<X_TO>\n yyerror("newline in recipient");
<X_HOURS>[[:digit:]]{1,2} hour = strtol(yytext, NULL, 10);
<X_HOURS>":" if (hour == -1) yyerror("illegal time: no hour specified"); else BEGIN(X_MINUTES);
<X_HOURS>\t+ yyerror("illegal time: no minutes specified");
<X_HOURS>.|\n yyerror("illegal time: bad number (hour)");
<X_MINUTES>\t+ if (minutes == -1) yyerror("illegal time: no minutes specified"); else BEGIN(X_SIZE);
<X_MINUTES>[[:digit:]]{2} minutes = strtol(yytext, NULL, 10);
<X_MINUTES>.|\n yyerror("illegal time: bad number (minutes)");
<X_SIZE>[ \t]+ ; /* ignore */
<X_SIZE>[[:digit:]]+ size = strtol(yytext, NULL, 10);
<X_SIZE>"KB" multiplier = 1;
<X_SIZE>"MB" multiplier = 1024;
<X_SIZE>. yyerror("bad character for size");
<X_SIZE>\n {
size *= multiplier;
sizesBySender[sender] += size;
sizesByHour[hour] += size;
BEGIN(INITIAL); subject = "";
}
<X_STRING>\\\" strlit += yytext;
<X_STRING>\" strlit += yytext; yy_pop_state(); *current += strlit;
<X_STRING>. strlit += yytext;
<X_STRING>\n yyerror("newline in string");
%%
The main function appears in the final section of the lexical specification. The actions performed by this function are the following: call the lexical analyzer; extract the map entries corresponding to the maximum size by sender and maximum size by hour; and, finally, present those entries in the standard output.
int main() {
typedef SIMT::value_type SIVT;
typedef IIMT::value_type IIVT;
yylex();
SIMT::iterator sender = std::max_element(sizesBySender.begin(), sizesBySender.end(),
[](SIVT &a, SIVT &b){return a.second < b.second;});
IIMT::iterator hour = std::max_element(sizesByHour.begin(), sizesByHour.end(),
[](IIVT &a, IIVT &b){return a.second < b.second;});
std::cout << sender->first << ", " << sender->second << std::endl;
std::cout << hour->first << ", " << hour->second << std::endl;
return 0;
}
Note that we are using features from C++11, namely, lambda functions. These are ultimately not necessary, but they make the code more compact.
The command for supporting these features in GCC is the following:
flex list-accounting.l g++ -o list-accounting lex.yy.c -std=c++11
To execute the program, and assuming that a list is file mylist.txt, do the following:
./list-accounting < mylist.txt