%{ #include #include #include #include #include #include #include "cparse.hpp" #include "cparse_def.h" /* to enable tracing, define ENABLE_PARSER_TRACE. may also want to invoke * bison with "-v" (by changing Makefile.am). */ #undef ENABLE_PARSER_TRACE #ifdef ENABLE_PARSER_TRACE #define YYDEBUG 1 #endif // ENABLE_PARSER_TRACE using namespace std; using namespace cnode; // stuff from lex extern "C" { extern int cparse_lineno; extern char *cparse_text; int cparse_lex(); void cparse_set_in(FILE *fin); } static void cparse_error(const char *s) { printf("Invalid config file (%s): error at line %d, text [%s]\n", s, cparse_lineno, cparse_text); } static int ndeact = 0; static char *ncomment = NULL; static char *nname = NULL; static char *nval = NULL; // XXX optimize: use unordered_map with non-vector static map, CfgNode *> node_map; static Cstore *cstore = NULL; static CfgNode *cur_node = NULL; static CfgNode *cur_parent = NULL; static vector cur_path; static vector pcomps; static vector pcomp_is_value; static void add_node() { pcomps.push_back(nname); CfgNode *onode = NULL; if (node_map.find(pcomps) != node_map.end()) { onode = node_map[pcomps]; } pcomps.pop_back(); if (onode) { if (nval) { if (onode->isMulti()) { // a new value for a "multi node" onode->addMultiValue(nval); cur_node = onode; } else if (onode->isTag()) { // a new value for a "tag node" cur_node = new CfgNode(pcomps, nname, nval, ncomment, ndeact, cstore); onode->addChildNode(cur_node); } else { /* a new value for a single-value node => invalid? * for now, use the newer value. */ cur_node = onode; cur_node->setValue(nval); } } else { // existing intermediate node => move current node pointer cur_node = onode; } } else { // new node cur_node = new CfgNode(pcomps, nname, nval, ncomment, ndeact, cstore); CfgNode *mapped_node = cur_node; if (cur_node->isTag() && cur_node->isValue()) { // tag value => need to add the "tag node" on top // (need to force "tag" if the node is invalid => tag_if_invalid) CfgNode *p = new CfgNode(pcomps, nname, NULL, NULL, ndeact, cstore, true); p->addChildNode(cur_node); mapped_node = p; } cur_parent->addChildNode(mapped_node); pcomps.push_back(nname); node_map[pcomps] = mapped_node; pcomps.pop_back(); } } static void go_down() { cur_path.push_back(cur_parent); cur_parent = cur_node; pcomps.push_back(nname); pcomp_is_value.push_back(false); if (nval) { pcomps.push_back(nval); pcomp_is_value.push_back(true); } } static void go_up() { cur_parent = cur_path.back(); cur_path.pop_back(); if (pcomp_is_value.back()) { pcomps.pop_back(); pcomp_is_value.pop_back(); } pcomps.pop_back(); pcomp_is_value.pop_back(); } %} %token NODE %token VALUE %token COMMENT %token LEFTB %token RIGHTB %token SYNTAX_ERROR %% input: forest comment ; forest: /* empty */ | forest tree ; tree: node { add_node(); } | node { add_node(); } LEFTB { go_down(); } forest RIGHTB { go_up(); } ; node: nodec { nval = NULL; } | nodec VALUE { nval = $2.str; } ; nodec: NODE { ncomment = NULL; nname = $1.str; ndeact = $1.deactivated; } | COMMENT NODE { ncomment = $1.str; nname = $2.str; ndeact = $2.deactivated; } ; comment: /* empty */ | COMMENT comment ; %% CfgNode * cparse::parse_file(FILE *fin, Cstore& cs) { // for debug (see prologue) #ifdef ENABLE_PARSER_TRACE cparse_debug = 1; #endif // ENABLE_PARSER_TRACE // initial state cparse_set_in(fin); cstore = &cs; ndeact = 0; ncomment = NULL; nname = NULL; nval = NULL; node_map.clear(); pcomps.clear(); pcomp_is_value.clear(); cur_path.clear(); cur_node = NULL; cur_parent = new CfgNode(pcomps, nname, nval, ncomment, ndeact, cstore); if (cparse_parse() != 0) { // parsing failed return NULL; } if (cur_path.size() > 0) { // didn't return to top-level => invalid return NULL; } return cur_parent; } CfgNode * cparse::parse_file(const char *fname, Cstore& cs) { FILE *fin = fopen(fname, "r"); if (!fin) { return NULL; } return parse_file(fin, cs); }