%{ #include #include #include #include #include #include "cparse.hpp" #include "cparse_def.h" using namespace cstore; using namespace cnode; using namespace cparse; /* 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 // 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; typedef MapT NmapT; static NmapT node_map; static Cstore *cstore_ = NULL; static CfgNode *cur_node = NULL; static CfgNode *cur_parent = NULL; static vector cur_path; static Cpath pcomps; static vector pcomp_is_value; static void cparse_init() { cstore_ = NULL; ndeact = 0; ncomment = NULL; nname = NULL; nval = NULL; node_map.clear(); pcomps.clear(); pcomp_is_value.clear(); cur_path.clear(); cur_node = NULL; } static void cparse_cleanup() { delete cur_node; free(nval); free(nname); free(ncomment); cparse_init(); } static void add_node() { pcomps.push(nname); CfgNode *onode = NULL; NmapT::iterator it = node_map.find(pcomps); if (it != node_map.end()) { onode = it->second; } pcomps.pop(); 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(nname); node_map[pcomps] = mapped_node; pcomps.pop(); } } static void cleanup_node() { free(nval); free(nname); free(ncomment); nval = ncomment = nname = NULL; } static void go_down() { cur_path.push_back(cur_parent); cur_parent = cur_node; pcomps.push(nname); pcomp_is_value.push_back(false); if (nval) { pcomps.push(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(); pcomp_is_value.pop_back(); } pcomps.pop(); 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(); cleanup_node(); } | node { add_node(); } LEFTB { go_down(); cleanup_node(); } forest comment RIGHTB { go_up(); } ; node: nodec { if (nval) free(nval); nval = NULL; } | nodec VALUE { nval = $2.str; } ; nodec: NODE { if (ncomment) free(ncomment); ncomment = NULL; nname = $1.str; ndeact = $1.deactivated; } | COMMENT comment NODE { ncomment = $1.str; nname = $3.str; ndeact = $3.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_init(); cparse_set_in(fin); cstore_ = &cs; cur_parent = new CfgNode(pcomps, nname, nval, ncomment, ndeact, cstore_); if (cparse_parse() != 0) { // parsing failed cparse_cleanup(); return NULL; } if (cur_path.size() > 0) { // didn't return to top-level => invalid cparse_cleanup(); return NULL; } return cur_parent; } CfgNode * cparse::parse_file(const char *fname, Cstore& cs) { CfgNode *ret; FILE *fin = fopen(fname, "r"); if (!fin) { return NULL; } ret = parse_file(fin, cs); cparse_init(); fclose(fin); return ret; }