diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-07-13 13:59:25 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-07-13 14:02:32 +0300 |
commit | 34ebfd8b58b7e7e37fbe335c7dca5e16ff2f1327 (patch) | |
tree | b146d48bcdc05ba4c4871567787b12f3571732d5 /src | |
parent | a2d8ce64b682996aebfc1182f3af1a66454bd449 (diff) | |
download | mailfromd-34ebfd8b58b7e7e37fbe335c7dca5e16ff2f1327.tar.gz mailfromd-34ebfd8b58b7e7e37fbe335c7dca5e16ff2f1327.tar.bz2 |
Implement enumerations in MFL
* src/gram.y: Implement enumerated constant definitions.
* src/mailfromd.h (define_constant): Remove const from the
return type.
* src/symbols.c: Likewise.
* tests/enum.at: New test.
* tests/Makefile.am: Add new test.
* tests/testsuite.at: Likewise.
* NEWS: Mention new features.
* doc/mailfromd.texi: Document new features.
Diffstat (limited to 'src')
-rw-r--r-- | src/gram.y | 117 | ||||
-rw-r--r-- | src/mailfromd.h | 6 | ||||
-rw-r--r-- | src/symbols.c | 3 |
3 files changed, 108 insertions, 18 deletions
@@ -340,6 +340,10 @@ _create_alias(void *item, void *data) struct { int code; } progspecial; + struct enumlist { + struct constant *cv; + struct enumlist *prev; + } enumlist; mu_list_t list; struct import_rule_list import_rule_list; char *string; @@ -470,8 +474,8 @@ _create_alias(void *item, void *data) %type <progspecial> progspecial %type <list> aliases aliasdecl %type <import_rule_list> imports -%type <number> qualifiers qualifier - +%type <number> qualifiers qualifier qualconst +%type <enumlist> enumlist constdefn %% input : program @@ -813,12 +817,26 @@ qualifier : T_PRECIOUS ; -constdecl : qualifiers T_CONST varname expr - /* FIXME: Optimize if varname: T_IDENTIFIER */ +constdecl : qualconst constdefn { - struct value value; - struct variable *pvar; + $2.cv->sym.flags = $1; + $$ = NULL; + } + | qualconst T_DO enumlist T_DONE + { + struct enumlist *elist; + while ((elist = $3.prev)) { + elist->cv->sym.flags = $1; + elist = elist->prev; + free($3.prev); + $3.prev = elist; + } + $$ = NULL; + } + ; +qualconst : qualifiers T_CONST + { if ($1 & SYM_PRECIOUS) parse_error_locus(&@1, _("`precious' used with const")); @@ -827,36 +845,107 @@ constdecl : qualifiers T_CONST varname expr parse_error_locus(&@1, _("`static' and `public' " "used together")); + $$ = $1; + } + ; + +constdefn : varname expr + /* FIXME: Optimize if varname: T_IDENTIFIER */ + { + struct value value; + struct variable *pvar; + /* FIXME: This is necessary because constants can be referred to the same way as variables. */ - if (pvar = variable_lookup($3->text)) { + if (pvar = variable_lookup($1->text)) { parse_warning(_("constant name `%s' clashes with a variable name"), - $3->text); + $1->text); parse_warning_locus(&pvar->sym.locus, _("this is the location of the " "previous definition")); } if (optimization_level) - optimize($4); + optimize($2); - switch ($4->type) { + switch ($2->type) { case node_type_string: value.type = dtype_string; - value.v.literal = $4->v.literal; + value.v.literal = $2->v.literal; break; case node_type_number: value.type = dtype_number; - value.v.number = $4->v.number; + value.v.number = $2->v.number; break; default: yyerror(_("initializer element is not constant")); YYERROR; } - define_constant($3->text, &value, $1, &@2); - $$ = NULL; + + $$.cv = define_constant($1->text, &value, 0, &@1); + $$.prev = NULL; + } + ; + +enumlist : varname + { + struct enumlist *elist; + struct value value; + struct variable *pvar; + + if (pvar = variable_lookup($1->text)) { + parse_warning(_("constant name `%s' clashes with a variable name"), + $1->text); + parse_warning_locus(&pvar->sym.locus, + _("this is the location of the " + "previous definition")); + } + + value.type = dtype_number; + value.v.number = 0; + + elist = mu_alloc(sizeof(*elist)); + + elist->cv = define_constant($1->text, &value, 0, &@1); + elist->prev = NULL; + $$.cv = NULL; + $$.prev = elist; + } + | constdefn + { + struct enumlist *elist = mu_alloc(sizeof(*elist)); + elist->cv = $1.cv; + elist->prev = NULL; + $$.cv = NULL; + $$.prev = elist; + } + | enumlist varname + { + if ($1.prev->cv->value.type == dtype_number) { + struct enumlist *elist = mu_alloc(sizeof(*elist)); + struct value value; + + value.type = dtype_number; + value.v.number = $1.prev->cv->value.v.number + 1; + + elist->cv = define_constant($2->text, &value, 0, + &@2); + elist->prev = $1.prev; + $$.prev = elist; + } else { + yyerror(_("initializer element is not numeric")); + YYERROR; + } + } + | enumlist constdefn + { + struct enumlist *elist = mu_alloc(sizeof(*elist)); + elist->cv = $2.cv; + elist->prev = $1.prev; + $1.prev = elist; + $$ = $1; } ; diff --git a/src/mailfromd.h b/src/mailfromd.h index 3739c956..3679c5e3 100644 --- a/src/mailfromd.h +++ b/src/mailfromd.h @@ -562,9 +562,9 @@ struct function *function_install(const char *name, const struct mu_locus_range *locus); struct function *function_lookup(const char *name); struct literal *literal_lookup(const char *text); -const struct constant *define_constant(const char *name, struct value *value, - unsigned flags, - struct mu_locus_range const *loc); +struct constant *define_constant(const char *name, struct value *value, + unsigned flags, + struct mu_locus_range const *loc); const struct constant *constant_lookup(const char *name); const struct value *constant_lookup_value(const char *name); diff --git a/src/symbols.c b/src/symbols.c index 7ba645aa..ec235e0b 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -928,7 +928,7 @@ literal_lookup(const char *text) } -const struct constant * +struct constant * define_constant(const char *name, struct value *value, unsigned flags, struct mu_locus_range const *locus) { @@ -939,6 +939,7 @@ define_constant(const char *name, struct value *value, unsigned flags, TOP_MODULE_SYMTAB(namespace_constant), name, &install); if (rc) { + parse_error(_("cannot install constant %s: %s"), name, symtab_strerror(rc)); abort(); |