aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2020-07-13 13:59:25 +0300
committerSergey Poznyakoff <gray@gnu.org>2020-07-13 14:02:32 +0300
commit34ebfd8b58b7e7e37fbe335c7dca5e16ff2f1327 (patch)
treeb146d48bcdc05ba4c4871567787b12f3571732d5 /src
parenta2d8ce64b682996aebfc1182f3af1a66454bd449 (diff)
downloadmailfromd-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.y117
-rw-r--r--src/mailfromd.h6
-rw-r--r--src/symbols.c3
3 files changed, 108 insertions, 18 deletions
diff --git a/src/gram.y b/src/gram.y
index fbc894af..74229aff 100644
--- a/src/gram.y
+++ b/src/gram.y
@@ -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();

Return to:

Send suggestions and report system problems to the System administrator.