/* parser.y (Bison file) */ %{ #define PARSER_SOURCE #include #include #include "system.pb.h" // Include the generated protobuf header #include "lexer.h" #define yylex lexer.yynlex using namespace std; Entry::System msg; bool legacy = true; %} %language "c++" %require "3.2" %define api.token.constructor %define api.value.type variant %define parse.error detailed %define parse.trace true %code requires // *.hh { #include #include "lexer.h" #include "location.h" } //%locations //%define api.location.type {yy::location} %parse-param {Lexer &lexer} %token ULONG %token FLOAT %token KEY %token BREAK BLANK START END VERSION CPU BASE USER NICE SWAP %token SYSP IDLE IOWP IRQP SIRQ CORE MEM TOTAL AVAIL CACHE TSENSOR %token SHARED TSWAP USWAP TEMP CURR TMIN TMAX TAVG COLON SLASH %% // Grammar Rules start: block | start block ; block: block_start data_block block_end ; block_start: START BLANK ULONG BREAK { cout << "begin\t" << $ULONG << endl; msg.set_epoch($3); } ; block_end: END BLANK ULONG BREAK { if ($3 == msg.epoch()) { cout << "end\t" << $ULONG << endl; auto p = filesystem::path("proto"); p /= to_string($3); p += string(".proto"); ofstream f(p, ios_base::out | ios_base::binary); msg.SerializeToOstream(&f); f.close(); } msg.Clear(); } data_block: version_block data_list | cpu_legacy_list mem_legacy tmp_legacy ; version_block: VERSION BLANK ULONG BLANK ULONG BREAK { legacy = false; cout << "ver\t" << $3 << "\t" << $5 << endl; } ; data_list: data BREAK | data BREAK data_list; data: CPU BLANK cpu_block | MEM BLANK mem_current | TEMP BLANK tmp_current ; cpu_percent: USER { $$ = 0; } | NICE { $$ = 1; } | SYSP { $$ = 2; } | IDLE { $$ = 3; } | IOWP { $$ = 4; } | IRQP { $$ = 5; } | SIRQ { $$ = 6; }; cpu_block: BASE BLANK FLOAT BLANK ULONG { ([&] (auto base) { base->set_usage($3); base->set_clock($5); cout << "cpu\tbase\t" << base->usage() << "\t" << base->clock() << endl; })(msg.mutable_cpu()->mutable_base()); } | cpu_percent BLANK FLOAT BLANK FLOAT { string name = ([&](auto t) { switch(t) { case token_type::USER: return "user"; case token_type::NICE: return "nice"; case token_type::SYSP: return "system"; case token_type::IDLE: return "idle"; case token_type::IOWP: return "iowait"; case token_type::IRQP: return "hwirq"; case token_type::SIRQ: return "swirq"; default: return "undef"; } })($1); ([&] (auto a, auto b) -> void { ::Entry::CPUStats_Subsystem sys; sys.set_curr(a); sys.set_diff(b); msg.mutable_cpu()->mutable_subsystem()->insert({name, sys}); cout << "cpu\t" << name << "%\t" << msg.cpu().subsystem().at(name).curr() << "\t" << msg.cpu().subsystem().at(name).diff() << endl; })($3, $5); } | CORE ULONG BLANK FLOAT BLANK ULONG { ([&] (auto core, auto a, auto b) -> void { ::Entry::CPUStats_Core c; c.set_usage(a); c.set_clock(b); msg.mutable_cpu()->mutable_cores()->insert({core, c}); cout << "cpu\tcore:" << core << "\t" << msg.cpu().cores().at(core).usage() << "\t" << msg.cpu().cores().at(core).clock() << endl; })($2, $4, $6); } ; mem_type: TOTAL { $$ = 1; } | AVAIL { $$ = 2; } | CACHE { $$ = 3; } | SHARED { $$ = 4; } | TSWAP { $$ = 5; } | USWAP { $$ = 6; } ; mem_current: mem_type BLANK ULONG { ([&](auto mem, int t, uint64_t v) { cout << "mem\t"; switch(t) { case token_type::TOTAL: mem->set_total(v); cout << "total\t" << msg.mem().total(); break; case token_type::AVAIL: mem->set_avail(v); cout << "avail\t" << msg.mem().avail(); break; case token_type::CACHE: mem->set_cache(v); cout << "cache\t" << msg.mem().cache(); break; case token_type::SHARED:mem->set_share(v); cout << "share\t" << msg.mem().share(); break; case token_type::TSWAP: mem->set_tswap(v); cout << "tswap\t" << msg.mem().tswap(); break; case token_type::USWAP: mem->set_uswap(v); cout << "uswap\t" << msg.mem().uswap(); break; default: cout << "undef\t" << v; break; } cout << endl; })(msg.mutable_mem(), yystack_[2].kind(), $ULONG); } ; tmp_type: CURR | TMIN | TMAX | TAVG; tmp_current: tmp_type BLANK ULONG { if (legacy) throw syntax_error("TEMP Block in legacy data."); using token = yy::parser::token::token_kind_type; ([&](auto tmp, int t, uint64_t v) { cout << "tmp\t"; switch(t) { case token::CURR: tmp->set_cur(v); cout << "cur\t" << tmp->cur(); break; case token::TMIN: tmp->set_min(v); cout << "min\t" << tmp->min(); break; case token::TMAX: tmp->set_max(v); cout << "max\t" << tmp->max(); break; case token::TAVG: tmp->set_avg(v); cout << "avg\t" << tmp->avg(); break; default: cout << "und\t" << v; break; } cout << endl; })(msg.mutable_tmp(), yystack_[2].kind(), $3); } ; cpu_legacy: CPU BLANK cpu_block; cpu_legacy_list: cpu_legacy BREAK | cpu_legacy BREAK cpu_legacy_list ; mem_legacy: mem_legacy_total mem_legacy_list BREAK; mem_legacy_total: MEM BLANK ULONG { msg.mutable_mem()->set_total($3); cout << "mem\t" << msg.mem().total(); } mem_legacy_type: AVAIL | CACHE | SHARED; mem_legacy_list: BLANK mem_legacy_data | mem_legacy_list BLANK mem_legacy_data ; mem_legacy_ram: mem_legacy_type COLON ULONG { ([&](auto mem, int t, uint64_t v) { switch(t) { case token_type::AVAIL: mem->set_avail(v); cout << "\tavail:" << msg.mem().avail(); break; case token_type::CACHE: mem->set_cache(v); cout << "\tcache:" << msg.mem().cache(); break; case token_type::SHARED:mem->set_share(v); cout << "\tshare:" << msg.mem().share(); break; default: cout << "\tundef:" << v; break; } })(msg.mutable_mem(), yystack_[2].kind(), $3); } ; mem_legacy_data: mem_legacy_ram | SWAP COLON ULONG SLASH ULONG { msg.mutable_mem()->set_tswap($5); msg.mutable_mem()->set_uswap($3); cout << "\n\t\t\tswap:" << msg.mem().uswap() << "/" << msg.mem().tswap() << endl; } ; tmp_legacy: tmp_legacy_block BREAK { if (! legacy) throw syntax_error("Unknown TEMP Block data."); cout << endl; }; tmp_legacy_block: tmp_legacy_id tmp_legacy_list | tmp_legacy_list; tmp_legacy_id: TEMP BLANK TSENSOR ULONG { cout << "tmp\tPackage id " << $ULONG; } ; tmp_legacy_list: BLANK tmp_legacy_data | tmp_legacy_list BLANK tmp_legacy_data; tmp_legacy_data: tmp_type COLON ULONG { using token = yy::parser::token::token_kind_type; ([&](auto tmp, token t, uint64_t v) { switch(t) { case token::CURR: tmp->set_cur(v); cout << "\tcur:" << msg.tmp().cur(); break; case token::TMIN: tmp->set_min(v); cout << "\tmin:" << msg.tmp().min(); break; case token::TMAX: tmp->set_max(v); cout << "\tmax:" << msg.tmp().max(); break; case token::TAVG: tmp->set_avg(v); cout << "\tavg:" << msg.tmp().avg(); break; default: cout << "\tund:" << v; break; } })(msg.mutable_tmp(), $1, $3); } %% namespace yy { // Report an error to the user. auto parser::error (const std::string& msg) -> void { std::cerr << msg << " on line " << lexer.lineno() << '\n'; } } int main() { Lexer lexer; yy::parser parse(lexer); return parse(); }