%{ #define YYSTYPE char* #include #include #include #include "rtrmgr_module.h" #include "libxorp/xorp.h" #include "libxorp/xlog.h" #include "conf_tree.hh" #include "conf_tree_node.hh" #include "template_tree.hh" #include "template_tree_node.hh" #include "config_operators.hh" /* XXX: sigh - -p flag to yacc should do this for us */ #define yystacksize bootstacksize #define yysslim bootsslim %} %token UPLEVEL %token DOWNLEVEL %token END %left ASSIGN_OPERATOR %token BOOL_VALUE %token UINT_VALUE %token UINTRANGE_VALUE %token IPV4_VALUE %token IPV4RANGE_VALUE %token IPV4NET_VALUE %token IPV6_VALUE %token IPV6RANGE_VALUE %token IPV6NET_VALUE %token MACADDR_VALUE %token URL_FILE_VALUE %token URL_FTP_VALUE %token URL_HTTP_VALUE %token URL_TFTP_VALUE %token LITERAL %token STRING %token ARITH %token INFIX_OPERATOR %token SYNTAX_ERROR %token CONFIG_NODE_ID %% input: /* empty */ | definition input | emptystatement input | syntax_error ; definition: long_nodename nodegroup | short_nodename long_nodegroup ; short_nodename: literal { push_path(); } ; long_nodename: literals { push_path(); } ; literal: LITERAL { node_id = ""; extend_path($1, NODE_VOID, node_id); } | CONFIG_NODE_ID LITERAL { node_id = $1; free($1); extend_path($2, NODE_VOID, node_id); } ; literals: literals literal | literal STRING { extend_path($2, NODE_TEXT, node_id); } | literal LITERAL { extend_path($2, NODE_TEXT, node_id); } | literal BOOL_VALUE { extend_path($2, NODE_BOOL, node_id); } | literal UINTRANGE_VALUE { extend_path($2, NODE_UINTRANGE, node_id); } | literal UINT_VALUE { extend_path($2, NODE_UINT, node_id); } | literal IPV4RANGE_VALUE { extend_path($2, NODE_IPV4RANGE, node_id); } | literal IPV4_VALUE { extend_path($2, NODE_IPV4, node_id); } | literal IPV4NET_VALUE { extend_path($2, NODE_IPV4NET, node_id); } | literal IPV6RANGE_VALUE { extend_path($2, NODE_IPV6RANGE, node_id); } | literal IPV6_VALUE { extend_path($2, NODE_IPV6, node_id); } | literal IPV6NET_VALUE { extend_path($2, NODE_IPV6NET, node_id); } | literal MACADDR_VALUE { extend_path($2, NODE_MACADDR, node_id); } | literal URL_FILE_VALUE { extend_path($2, NODE_URL_FILE, node_id); } | literal URL_FTP_VALUE { extend_path($2, NODE_URL_FTP, node_id); } | literal URL_HTTP_VALUE { extend_path($2, NODE_URL_HTTP, node_id); } | literal URL_TFTP_VALUE { extend_path($2, NODE_URL_TFTP, node_id); } ; nodegroup: long_nodegroup | END { pop_path(); } ; long_nodegroup: UPLEVEL statements DOWNLEVEL { pop_path(); } ; statements: /* empty string */ | statement statements ; statement: terminal | definition | emptystatement ; emptystatement: END ; term_literal: LITERAL { node_id = ""; extend_path($1, NODE_VOID, node_id); } | CONFIG_NODE_ID LITERAL { node_id = $1; free($1); extend_path($2, NODE_VOID, node_id);} ; terminal: term_literal END { terminal(strdup(""), NODE_VOID, OP_NONE); } | term_literal INFIX_OPERATOR STRING END { terminal($3, NODE_TEXT, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR BOOL_VALUE END { terminal($3, NODE_BOOL, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR UINTRANGE_VALUE END { terminal($3, NODE_UINTRANGE, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR UINT_VALUE END { terminal($3, NODE_UINT, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR IPV4RANGE_VALUE END { terminal($3, NODE_IPV4RANGE, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR IPV4_VALUE END { terminal($3, NODE_IPV4, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR IPV4NET_VALUE END { terminal($3, NODE_IPV4NET, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR IPV6RANGE_VALUE END { terminal($3, NODE_IPV6RANGE, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR IPV6_VALUE END { terminal($3, NODE_IPV6, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR IPV6NET_VALUE END { terminal($3, NODE_IPV6NET, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR MACADDR_VALUE END { terminal($3, NODE_MACADDR, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR URL_FILE_VALUE END { terminal($3, NODE_URL_FILE, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR URL_FTP_VALUE END { terminal($3, NODE_URL_FTP, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR URL_HTTP_VALUE END { terminal($3, NODE_URL_HTTP, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR URL_TFTP_VALUE END { terminal($3, NODE_URL_TFTP, boot_lookup_operator($2)); free($2); } | term_literal INFIX_OPERATOR ARITH END { terminal($3, NODE_ARITH, boot_lookup_operator($2)); free($2); } ; syntax_error: SYNTAX_ERROR { booterror("syntax error"); } ; %% extern void boot_scan_string(const char *configuration); extern int boot_linenum; extern "C" int bootparse(); extern int bootlex(); void booterror(const char *s) throw (ParseError); static ConfigTree *config_tree = NULL; static string boot_filename; static string lastsymbol; static string node_id; static void extend_path(char* segment, int type, const string& node_id_str) { lastsymbol = segment; string segment_copy = segment; free(segment); try { ConfigNodeId config_node_id(node_id_str); config_tree->extend_path(segment_copy, type, config_node_id); } catch (const InvalidString& e) { string s = c_format("Invalid config tree node ID: %s", e.str().c_str()); booterror(s.c_str()); } } static void push_path() { config_tree->push_path(); } static void pop_path() { config_tree->pop_path(); } static void terminal(char* value, int type, ConfigOperator op) { push_path(); lastsymbol = value; config_tree->terminal_value(string(value), type, op); free(value); pop_path(); } void booterror(const char *s) throw (ParseError) { string errmsg; if (! boot_filename.empty()) { errmsg = c_format("PARSE ERROR [Config File %s, line %d]: %s", boot_filename.c_str(), boot_linenum, s); } else { errmsg = c_format("PARSE ERROR [line %d]: %s", boot_linenum, s); } errmsg += c_format("; Last symbol parsed was \"%s\"", lastsymbol.c_str()); xorp_throw(ParseError, errmsg); } int init_bootfile_parser(const char *configuration, const char *filename, ConfigTree *ct) { config_tree = ct; boot_filename = filename; boot_linenum = 1; boot_scan_string(configuration); return 0; } void parse_bootfile() throw (ParseError) { if (bootparse() != 0) booterror("unknown error"); } ConfigOperator boot_lookup_operator(const char* s) { char *s0, *s1, *s2; /* skip leading spaces */ s0 = strdup(s); s1 = s0; while (*s1 != '\0' && *s1 == ' ') { s1++; } /* trim trailing spaces */ s2 = s1; while (*s2 != '\0') { if (*s2 == ' ') { *s2 = 0; break; } s2++; } ConfigOperator op; string str = s1; free(s1); try { op = lookup_operator(str); return op; } catch (const ParseError& pe) { string errmsg = pe.why(); errmsg += c_format("\n[Line %d]\n", boot_linenum); errmsg += c_format("Last symbol parsed was \"%s\"", lastsymbol.c_str()); xorp_throw(ParseError, errmsg); } XLOG_UNREACHABLE(); }