diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-09-22 17:34:51 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-09-22 17:34:51 +0300 |
commit | 546c03672b5b8044dbca0814eac8cbdddb898183 (patch) | |
tree | 8277c3ad7efe0b60ce64aa563b70e7999238a7c6 /lib | |
parent | 8d16cf26fc6e3a6c91eec21892d9da58286479f0 (diff) | |
download | eclat-546c03672b5b8044dbca0814eac8cbdddb898183.tar.gz eclat-546c03672b5b8044dbca0814eac8cbdddb898183.tar.bz2 |
Introduce forlan functions.
* lib/forlan.c (forlan_find_function): New function.
(func_dump, func_print)
(func_error,func_parent): Function placeholders.
* lib/forlan.h (forlan_node_func) <fp>: Change datatype.
(forlan_eval_env_t): New typedef.
(forlan_value_type): New enum.
(forlan_value,forlan_function): New struct.
* lib/forlangrm.y: Check number of arguments passed to functions.
* tests/forlan01.at: Update.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/forlan.c | 52 | ||||
-rw-r--r-- | lib/forlan.h | 29 | ||||
-rw-r--r-- | lib/forlangrm.y | 50 |
3 files changed, 127 insertions, 4 deletions
diff --git a/lib/forlan.c b/lib/forlan.c index 0854d08..008ee5b 100644 --- a/lib/forlan.c +++ b/lib/forlan.c @@ -85,7 +85,7 @@ void dump_func(FILE *fp, union forlan_node *p, int *num, int lev) { struct grecs_list_entry *ep; - fprintf(fp, "CALL: %s\n", p->func.fp); + fprintf(fp, "CALL: %s\n", p->func.fp->name); if (p->func.args) for (ep = p->func.args->head; ep; ep = ep->next) forlan_dump_node(fp, ep->data, num, lev + 1); @@ -256,3 +256,53 @@ forlan_dump_tree(FILE *fp, union forlan_node *node) int n = 0; forlan_dump_node(fp, node, &n, 0); } + +struct forlan_eval_env { + struct grecs_node *tree; + struct grecs_node *last; +}; + +void +func_dump(forlan_eval_env_t env, struct grecs_list *list) +{ + abort(); +} + +void +func_print(forlan_eval_env_t env, struct grecs_list *list) +{ + abort(); +} + +void +func_error(forlan_eval_env_t env, struct grecs_list *list) +{ + abort(); +} + +void +func_parent(forlan_eval_env_t env, struct grecs_list *list) +{ + abort(); +} + +static struct forlan_function functab[] = { + { "dump", forlan_value_void, "n", 1, 1, func_dump }, + { "print", forlan_value_void, "", 1, -1, func_print }, + { "error", forlan_value_void, "", 1, -1, func_error }, + { "parent", forlan_value_node, "n", 1, 1, func_parent }, + { NULL } +}; + +struct forlan_function * +forlan_find_function(const char *name) +{ + struct forlan_function *fp; + for (fp = functab; fp->name; fp++) + if (strcmp(name, fp->name) == 0) + return fp; + return NULL; +} + + + diff --git a/lib/forlan.h b/lib/forlan.h index 4dadc70..aa4dbe4 100644 --- a/lib/forlan.h +++ b/lib/forlan.h @@ -58,7 +58,7 @@ struct forlan_node_test { /* Function call */ struct forlan_node_func { enum forlan_type type; - void *fp; /* FIXME: replace with typedef */ + struct forlan_function *fp; struct grecs_list *args; /* Arguments are struct forlan_node * */ }; @@ -121,3 +121,30 @@ extern union forlan_node *forlan_parse_tree; void forlan_dump_node(FILE *fp, union forlan_node *p, int *num, int lev); void forlan_dump_tree(FILE *fp, union forlan_node *node); + +typedef struct forlan_eval_env *forlan_eval_env_t; + +enum forlan_value_type { + forlan_value_void, + forlan_value_node, + forlan_value_literal +}; + +struct forlan_value { + enum forlan_value_type type; + union { + char *string; + struct grecs_node *node; + } v; +}; + +struct forlan_function { + char *name; + enum forlan_value_type rettype; + char *argtypes; + int minargs; + int maxargs; + void (*func)(forlan_eval_env_t, struct grecs_list *list); +}; + +struct forlan_function *forlan_find_function(const char *name); diff --git a/lib/forlangrm.y b/lib/forlangrm.y index 1b7781d..d2e0489 100644 --- a/lib/forlangrm.y +++ b/lib/forlangrm.y @@ -137,6 +137,12 @@ node : complist $$->comp.abs = 1; $$->comp.node = forlan_stmt_from_list($2); } + | '.' + { + $$ = forlan_node_create(forlan_type_comp); + $$->comp.abs = 1; + $$->comp.node = NULL; + } | LAST { $$ = forlan_node_create(forlan_type_last); @@ -175,14 +181,54 @@ string : IDENT funcall : IDENT '(' ')' { + struct forlan_function *fp = + forlan_find_function($1); + if (!fp) { + grecs_error(&@1, 0, + "call to unknown function \"%s\"", + $1); + YYERROR; + } + + if (fp->minargs != 0) { + grecs_error(&@1, 0, + "not enough arguments in call to \"%s\"", + $1); + YYERROR; + } + $$ = forlan_node_create(forlan_type_func); - $$->func.fp = $1; //FIXME + $$->func.fp = fp; $$->func.args = NULL; } | IDENT '(' arglist ')' { + struct forlan_function *fp = + forlan_find_function($1); + if (!fp) { + grecs_error(&@1, 0, + "call to unknown function \"%s\"", + $1); + YYERROR; + } + + if ($3->count < fp->minargs) { + grecs_error(&@1, 0, + "not enough arguments in call to \"%s\"", + $1); + YYERROR; + } + if (fp->maxargs >= 0 && $3->count > fp->minargs) { + grecs_error(&@1, 0, + "too many arguments in call to \"%s\"", + $1); + YYERROR; + } + + /* FIXME: Check data types */ + $$ = forlan_node_create(forlan_type_func); - $$->func.fp = $1; //FIXME + $$->func.fp = fp; $$->func.args = $3; } ; |