0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-29 18:22:50 +01:00
construct/ircd/ircd_parser.yy
Jason Volk 9d0a959bb5 MAPI IV. This iteration leverages the C++11 standardized RTTI.
* Simplifies the export declarations for module developers. While
MAPI III utilized a flexible key-value vector to eliminate positional
arguments in a header initializer, now the developer simply makes
a list of pointers to what they want to export for injection into
IRCd. Example:

mapi::header IRCD_MODULE
{
	"mymod",
	"My module adds a command, a hook, and a CLICAP",
	&my_cmdtab,
	&some_hook,
	&clicaptab
};

* Distributes the handlers for items passed to the above vector.
Anyone can add a type-handler to the module system from anywhere in IRCd
(and other modules?) When your type is encountered a handler is called
providing the symbol name to read out of the module. Example in parser.cc:

mods::add_loader<Message>([]
(mod &loading, const std::string &symbol)
{
	auto &msg(get<Message>(loading, symbol));
	add_command(msg.name, msg);
});
2016-09-09 16:17:01 -07:00

313 lines
5.7 KiB
Text

/* This code is in the public domain.
* $Nightmare: nightmare/src/main/parser.y,v 1.2.2.1.2.1 2002/07/02 03:42:10 ejb Exp $
*/
%{
#define YY_NO_UNPUT
int yylex();
namespace ircd {
static time_t conf_find_time(char*);
static struct {
const char * name;
const char * plural;
time_t val;
} ircd_times[] = {
{"second", "seconds", 1},
{"minute", "minutes", 60},
{"hour", "hours", 60 * 60},
{"day", "days", 60 * 60 * 24},
{"week", "weeks", 60 * 60 * 24 * 7},
{"fortnight", "fortnights", 60 * 60 * 24 * 14},
{"month", "months", 60 * 60 * 24 * 7 * 4},
{"year", "years", 60 * 60 * 24 * 365},
/* ok-- we now do sizes here too. they aren't times, but
it's close enough */
{"byte", "bytes", 1},
{"kb", NULL, 1024},
{"kbyte", "kbytes", 1024},
{"kilobyte", "kilebytes", 1024},
{"mb", NULL, 1024 * 1024},
{"mbyte", "mbytes", 1024 * 1024},
{"megabyte", "megabytes", 1024 * 1024},
{NULL, NULL, 0},
};
time_t conf_find_time(char *name)
{
int i;
for (i = 0; ircd_times[i].name; i++)
{
if (rb_strcasecmp(ircd_times[i].name, name) == 0 ||
(ircd_times[i].plural && rb_strcasecmp(ircd_times[i].plural, name) == 0))
return ircd_times[i].val;
}
return 0;
}
static struct
{
const char *word;
int yesno;
} yesno[] = {
{"yes", 1},
{"no", 0},
{"true", 1},
{"false", 0},
{"on", 1},
{"off", 0},
{NULL, 0}
};
static int conf_get_yesno_value(char *str)
{
int i;
for (i = 0; yesno[i].word; i++)
{
if (rb_strcasecmp(str, yesno[i].word) == 0)
{
return yesno[i].yesno;
}
}
return -1;
}
static void free_cur_list(conf_parm_t* list)
{
if (list->type == CF_STRING || list->type == CF_QSTRING) {
rb_free(list->v.string);
} else if (list->type == CF_FLIST) {
/* Even though CF_FLIST is a flag, comparing with == is valid
* because conf_parm_t.type must be either a type or one flag.
*/
free_cur_list(list->v.list);
}
if (list->next) {
free_cur_list(list->next);
}
rb_free(list);
}
conf_parm_t * cur_list;
static void add_cur_list_cpt(conf_parm_t *new_)
{
if (cur_list == NULL)
{
cur_list = (conf_parm_t *)rb_malloc(sizeof(conf_parm_t));
cur_list->type = CF_FLIST;
cur_list->v.list = new_;
}
else
{
new_->next = cur_list->v.list;
cur_list->v.list = new_;
}
}
static void add_cur_list(int type, char *str, int number)
{
conf_parm_t *new_;
new_ = (conf_parm_t *)rb_malloc(sizeof(conf_parm_t));
new_->next = NULL;
new_->type = type;
switch(type)
{
case CF_INT:
case CF_TIME:
case CF_YESNO:
new_->v.number = number;
break;
case CF_STRING:
case CF_QSTRING:
new_->v.string = rb_strdup(str);
break;
}
add_cur_list_cpt(new_);
}
} // namespace ircd
%}
%union {
int number;
char string[1024];
ircd::conf_parm_t * conf_parm;
}
%token LOADMODULE TWODOTS
%token <string> QSTRING STRING
%token <number> NUMBER
%type <string> qstring string
%type <number> number timespec
%type <conf_parm> oneitem single itemlist
%start conf
%%
conf:
| conf conf_item
| error
;
conf_item: block
| loadmodule
;
block: string
{
ircd::conf_start_block($1, NULL);
}
'{' block_items '}' ';'
{
if (ircd::conf_cur_block)
ircd::conf_end_block(ircd::conf_cur_block);
}
| string qstring
{
ircd::conf_start_block($1, $2);
}
'{' block_items '}' ';'
{
if (ircd::conf_cur_block)
ircd::conf_end_block(ircd::conf_cur_block);
}
;
block_items: block_items block_item
| block_item
;
block_item: string '=' itemlist ';'
{
ircd::conf_call_set(ircd::conf_cur_block, $1, ircd::cur_list);
ircd::free_cur_list(ircd::cur_list);
ircd::cur_list = NULL;
}
;
itemlist: itemlist ',' single
| single
;
single: oneitem
{
ircd::add_cur_list_cpt($1);
}
| oneitem TWODOTS oneitem
{
/* "1 .. 5" meaning 1,2,3,4,5 - only valid for integers */
if ($1->type != CF_INT || $3->type != CF_INT)
{
ircd::conf_report_error("Both arguments in '..' notation must be integers.");
break;
}
else
{
int i;
for (i = $1->v.number; i <= $3->v.number; i++)
{
ircd::add_cur_list(CF_INT, 0, i);
}
}
}
;
oneitem: qstring
{
$$ = (ircd::conf_parm_t *)rb_malloc(sizeof(ircd::conf_parm_t));
$$->type = CF_QSTRING;
$$->v.string = rb_strdup($1);
}
| timespec
{
$$ = (ircd::conf_parm_t *)rb_malloc(sizeof(ircd::conf_parm_t));
$$->type = CF_TIME;
$$->v.number = $1;
}
| number
{
$$ = (ircd::conf_parm_t *)rb_malloc(sizeof(ircd::conf_parm_t));
$$->type = CF_INT;
$$->v.number = $1;
}
| string
{
/* a 'string' could also be a yes/no value ..
so pass it as that, if so */
int val = ircd::conf_get_yesno_value($1);
$$ = (ircd::conf_parm_t *)rb_malloc(sizeof(ircd::conf_parm_t));
if (val != -1)
{
$$->type = CF_YESNO;
$$->v.number = val;
}
else
{
$$->type = CF_STRING;
$$->v.string = rb_strdup($1);
}
}
;
loadmodule:
LOADMODULE QSTRING
{
char *m_bn;
m_bn = rb_basename((char *) $2);
if (!ircd::mods::loaded(m_bn))
{
ircd::mods::load($2);
}
rb_free(m_bn);
}
';'
;
qstring: QSTRING { strcpy($$, $1); } ;
string: STRING { strcpy($$, $1); } ;
number: NUMBER { $$ = $1; } ;
timespec: number string
{
time_t t;
if ((t = ircd::conf_find_time($2)) == 0)
{
ircd::conf_report_error("Unrecognised time type/size '%s'", $2);
t = 1;
}
$$ = $1 * t;
}
| timespec timespec
{
$$ = $1 + $2;
}
| timespec number
{
$$ = $1 + $2;
}
;