Implement config parser

This commit is contained in:
Matthias Schiffer 2013-07-28 22:12:35 +02:00
parent a713d2931e
commit 37c2167874
5 changed files with 164 additions and 34 deletions

View file

@ -26,6 +26,8 @@
#include "context.hpp"
#include "network.hpp"
#include "node.hpp"
#include "protocol.hpp"
#include <config.ll.hpp>
#include <config.yy.hpp>
@ -38,12 +40,83 @@
namespace MMSS {
void config_t::add_network(const char *name) {
mmss->logf(LOG_NOTICE, "adding network `%s'", name);
bool config_t::load_proto(const char *name, const char *module, bool def) {
if (protos.find(name) != protos.end()) {
mmss->logf(LOG_ERR, "config error: duplicate protocol `%s'", name);
return false;
}
network.push_back(std::make_shared<network_t>(name));
std::shared_ptr<const protocol_t> proto = protocol_t::load(mmss, module);
if (!proto)
return false;
if (def)
default_proto = proto;
protos.insert(std::make_pair(name, std::move(proto)));
return true;
}
bool config_t::add_network(const char *name) {
if (networks.find(name) != networks.end()) {
mmss->logf(LOG_ERR, "config error: duplicate network `%s'", name);
return false;
}
networks.insert(std::make_pair(name, std::make_shared<network_t>(name)));
return true;
}
bool config_t::add_node(const char *name, const char *proto) {
if (nodes.find(name) != nodes.end()) {
mmss->logf(LOG_ERR, "config error: duplicate node `%s'", name);
return false;
}
const std::shared_ptr<const protocol_t> *proto_ptr = &default_proto;
if (proto) {
auto it = protos.find(proto);
if (it == protos.end()) {
mmss->logf(LOG_ERR, "config error: no protocol `%s' found", proto);
return false;
}
proto_ptr = &it->second;
}
if (!*proto_ptr) {
mmss->logf(LOG_ERR, "config error: node `%s': no protocol given and no default protocol defined", name);
return false;
}
current_node = &nodes.insert(std::make_pair(name, node_t::create(mmss, name, rand_seed++, *proto_ptr))).first->second;
return true;
}
bool config_t::add_iface(const char *name, const char *net, const gmrf_addr_t *addr) {
// TODO duplicate name, address check
auto it = networks.find(net);
if (it == networks.end()) {
mmss->logf(LOG_ERR, "config error: no network `%s' found", net);
return false;
}
iface_t::add(*current_node, it->second, name, addr);
return true;
}
std::shared_ptr<const config_t> config_t::read(context_t *mmss, const char *filename) {
std::shared_ptr<config_t> conf = std::shared_ptr<config_t>(new config_t(mmss));
char *oldcwd = get_current_dir_name();

View file

@ -28,8 +28,9 @@
#include "types.hpp"
#include <list>
#include <memory>
#include <string>
#include <unordered_map>
namespace MMSS {
@ -38,17 +39,27 @@ class config_t : public nocopy_t {
private:
context_t *mmss;
std::list<std::shared_ptr<network_t>> network;
std::list<std::shared_ptr<node_t>> nodes;
int rand_seed;
config_t(context_t *mmss0) : mmss(mmss0) {}
std::shared_ptr<const protocol_t> default_proto;
std::unordered_map<std::string, std::shared_ptr<const protocol_t>> protos;
std::unordered_map<std::string, std::shared_ptr<network_t>> networks;
const std::shared_ptr<node_t> *current_node;
std::unordered_map<std::string, std::shared_ptr<node_t>> nodes;
config_t(context_t *mmss0) : mmss(mmss0), rand_seed(0) {}
public:
context_t* get_context() const {
return mmss;
}
void add_network(const char *name);
bool load_proto(const char *name, const char *module, bool def);
bool add_network(const char *name);
bool add_node(const char *name, const char *proto);
bool add_iface(const char *name, const char *net, const gmrf_addr_t *addr);
static std::shared_ptr<const config_t> read(context_t *mmss, const char *filename);
};

View file

@ -36,6 +36,9 @@
%top {
#include <config.yy.hpp>
#include <cassert>
#include <cstdio>
}
%s NEEDSPACE
@ -59,6 +62,22 @@
yes { TOKEN(TOK_YES); }
no { TOKEN(TOK_NO); }
network { TOKEN(TOK_NETWORK); }
protocol { TOKEN(TOK_PROTOCOL); }
node { TOKEN(TOK_NODE); }
load { TOKEN(TOK_LOAD); }
default { TOKEN(TOK_DEFAULT); }
interface { TOKEN(TOK_INTERFACE); }
address { TOKEN(TOK_ADDRESS); }
([[:xdigit:]]{2}:){7}[[:xdigit:]]{2} {
UPDATE_LOCATION;
assert(std::sscanf(yytext, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&yylval->addr.d[0], &yylval->addr.d[1], &yylval->addr.d[2], &yylval->addr.d[3],
&yylval->addr.d[4], &yylval->addr.d[5], &yylval->addr.d[6], &yylval->addr.d[7]) == 8);
return TOK_GMRF_ADDRESS;
}
[;:\{\}] { UPDATE_LOCATION; return yytext[0]; }

View file

@ -43,16 +43,24 @@
int num;
bool boolean;
char *str;
gmrf_addr_t addr;
const char *error;
}
%token <num> TOK_INTEGER
%token <str> TOK_STRING
%token <addr> TOK_GMRF_ADDRESS
%token TOK_NETWORK
%token TOK_YES
%token TOK_NO
%token TOK_NETWORK
%token TOK_PROTOCOL
%token TOK_NODE
%token TOK_LOAD
%token TOK_DEFAULT
%token TOK_INTERFACE
%token TOK_ADDRESS
%code {
@ -61,6 +69,8 @@
%type <boolean> boolean
%type <boolean> maybe_default
%type <str> maybe_protocol
%%
@ -72,20 +82,56 @@ config: config statement
;
statement: TOK_NETWORK network '{' network_config '}'
| TOK_PROTOCOL protocol ';'
| TOK_NODE node '{' node_config '}'
;
network: TOK_STRING {
conf->add_network($1);
if (!conf->add_network($1))
YYERROR;
}
;
network_config:
;
protocol: TOK_STRING TOK_LOAD TOK_STRING maybe_default {
if (!conf->load_proto($1, $3, $4))
YYERROR;
}
;
node: TOK_STRING maybe_protocol {
if (!conf->add_node($1, $2))
YYERROR;
}
;
node_config: node_config node_statement
|
;
node_statement: TOK_INTERFACE node_interface ';'
;
node_interface: TOK_STRING TOK_NETWORK TOK_STRING TOK_ADDRESS TOK_GMRF_ADDRESS {
if (!conf->add_iface($1, $3, &$5))
YYERROR;
}
;
boolean: TOK_YES { $$ = true; }
| TOK_NO { $$ = false; }
;
maybe_default: TOK_DEFAULT { $$ = true; }
| { $$ = false; }
;
maybe_protocol: TOK_PROTOCOL TOK_STRING { $$ = $2; }
| { $$ = nullptr; }
;
%%
void mmss_config_error(YYLTYPE *loc, const std::shared_ptr<config_t> &conf, const char *filename, const char *s) {

View file

@ -88,35 +88,16 @@ void context_t::logf(int priority, const char *format, ...) {
void context_t::run(int argc, char *argv[]) {
if (argc != 2) {
std::fprintf(stderr, "usage: %s protocol_module\n", argv[0]);
std::fprintf(stderr, "usage: %s config\n", argv[0]);
std::exit(1);
}
std::shared_ptr<const protocol_t> proto = protocol_t::load(this, argv[1]);
if (!proto)
std::shared_ptr<const config_t> conf = config_t::read(this, argv[1]);
if (!conf)
std::exit(1);
std::shared_ptr<const config_t> conf = config_t::read(this, "babel_test.mmss");
std::shared_ptr<network_t> net0 = std::make_shared<network_t>("net0");
std::shared_ptr<network_t> net1 = std::make_shared<network_t>("net1");
std::shared_ptr<node_t> node1 = node_t::create(this, "node1", 1, proto);
std::shared_ptr<node_t> node2 = node_t::create(this, "node2", 2, proto);
std::shared_ptr<node_t> node3 = node_t::create(this, "node3", 3, proto);
std::list<std::shared_ptr<node_t>> nodes;
nodes.push_back(node1);
nodes.push_back(node2);
nodes.push_back(node3);
gmrf_addr_t addr1 = {{1}}, addr2 = {{2}}, addr3 = {{3}}, addr4 = {{4}};
iface_t::add(node1, net0, "mmss0", &addr1);
iface_t::add(node2, net0, "mmss0", &addr2);
iface_t::add(node2, net1, "mmss1", &addr3);
iface_t::add(node3, net1, "mmss1", &addr4);
while (true) {
if (now() > 10000000)
break;