123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- /*
- * Copyright (c) 2014 Hugh Bailey <[email protected]>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include "../util/cf-parser.h"
- #include "decl.h"
- static inline void err_specifier_exists(struct cf_parser *cfp,
- const char *storage)
- {
- cf_adderror(cfp, "'$1' specifier already exists", LEX_ERROR,
- storage, NULL, NULL);
- }
- static inline void err_reserved_name(struct cf_parser *cfp, const char *name)
- {
- cf_adderror(cfp, "'$1' is a reserved name", LEX_ERROR,
- name, NULL, NULL);
- }
- static inline void err_existing_name(struct cf_parser *cfp, const char *name)
- {
- cf_adderror(cfp, "'$1' already exists", LEX_ERROR, name, NULL, NULL);
- }
- static bool is_in_out_specifier(struct cf_parser *cfp, struct strref *name,
- uint32_t *type)
- {
- if (strref_cmp(name, "in") == 0) {
- if (*type & CALL_PARAM_IN)
- err_specifier_exists(cfp, "in");
- *type |= CALL_PARAM_IN;
- } else if (strref_cmp(name, "out") == 0) {
- if (*type & CALL_PARAM_OUT)
- err_specifier_exists(cfp, "out");
- *type |= CALL_PARAM_OUT;
- } else {
- return false;
- }
- return true;
- }
- #define TYPE_OR_STORAGE "type or storage specifier"
- static bool get_type(struct strref *ref, enum call_param_type *type,
- bool is_return)
- {
- if (strref_cmp(ref, "int") == 0)
- *type = CALL_PARAM_TYPE_INT;
- else if (strref_cmp(ref, "float") == 0)
- *type = CALL_PARAM_TYPE_FLOAT;
- else if (strref_cmp(ref, "bool") == 0)
- *type = CALL_PARAM_TYPE_BOOL;
- else if (strref_cmp(ref, "ptr") == 0)
- *type = CALL_PARAM_TYPE_PTR;
- else if (strref_cmp(ref, "string") == 0)
- *type = CALL_PARAM_TYPE_STRING;
- else if (is_return && strref_cmp(ref, "void") == 0)
- *type = CALL_PARAM_TYPE_VOID;
- else
- return false;
- return true;
- }
- static bool is_reserved_name(const char *str)
- {
- return (strcmp(str, "int") == 0) ||
- (strcmp(str, "float") == 0) ||
- (strcmp(str, "bool") == 0) ||
- (strcmp(str, "ptr") == 0) ||
- (strcmp(str, "string") == 0) ||
- (strcmp(str, "void") == 0) ||
- (strcmp(str, "return") == 0);
- }
- static bool name_exists(struct decl_info *decl, const char *name)
- {
- for (size_t i = 0; i < decl->params.num; i++) {
- const char *param_name = decl->params.array[i].name;
- if (strcmp(name, param_name) == 0)
- return true;
- }
- return false;
- }
- static int parse_param(struct cf_parser *cfp, struct decl_info *decl)
- {
- struct strref ref;
- int code;
- struct decl_param param = {0};
- /* get storage specifiers */
- code = cf_next_name_ref(cfp, &ref, TYPE_OR_STORAGE, ",");
- if (code != PARSE_SUCCESS)
- return code;
- while (is_in_out_specifier(cfp, &ref, ¶m.flags)) {
- code = cf_next_name_ref(cfp, &ref, TYPE_OR_STORAGE, ",");
- if (code != PARSE_SUCCESS)
- return code;
- }
- /* parameters not marked with specifiers are input parameters */
- if (param.flags == 0)
- param.flags = CALL_PARAM_IN;
- if (!get_type(&ref, ¶m.type, false)) {
- cf_adderror_expecting(cfp, "type");
- cf_go_to_token(cfp, ",", ")");
- return PARSE_CONTINUE;
- }
- /* name */
- code = cf_next_name(cfp, ¶m.name, "parameter name", ",");
- if (code != PARSE_SUCCESS)
- return code;
- if (name_exists(decl, param.name))
- err_existing_name(cfp, param.name);
- if (is_reserved_name(param.name))
- err_reserved_name(cfp, param.name);
- da_push_back(decl->params, ¶m);
- return PARSE_SUCCESS;
- }
- static void parse_params(struct cf_parser *cfp, struct decl_info *decl)
- {
- struct cf_token peek;
- int code;
- if (!cf_peek_valid_token(cfp, &peek))
- return;
- while (peek.type == CFTOKEN_NAME) {
- code = parse_param(cfp, decl);
- if (code == PARSE_EOF)
- return;
- if (code != PARSE_CONTINUE && !cf_next_valid_token(cfp))
- return;
- if (cf_token_is(cfp, ")"))
- break;
- else if (cf_token_should_be(cfp, ",", ",", NULL) == PARSE_EOF)
- return;
- if (!cf_peek_valid_token(cfp, &peek))
- return;
- }
- if (!cf_token_is(cfp, ")"))
- cf_next_token_should_be(cfp, ")", NULL, NULL);
- }
- static void print_errors(struct cf_parser *cfp, const char *decl_string)
- {
- char *errors = error_data_buildstring(&cfp->error_list);
- if (errors) {
- blog(LOG_WARNING, "Errors/warnings for '%s':\n\n%s",
- decl_string, errors);
- bfree(errors);
- }
- }
- bool parse_decl_string(struct decl_info *decl, const char *decl_string)
- {
- struct cf_parser cfp;
- struct strref ret_type;
- struct decl_param ret_param = {0};
- int code;
- bool success;
- decl->decl_string = decl_string;
- ret_param.flags = CALL_PARAM_OUT;
- cf_parser_init(&cfp);
- if (!cf_parser_parse(&cfp, decl_string, "declaration"))
- goto fail;
- code = cf_get_name_ref(&cfp, &ret_type, "return type", NULL);
- if (code == PARSE_EOF)
- goto fail;
- if (!get_type(&ret_type, &ret_param.type, true))
- cf_adderror_expecting(&cfp, "return type");
- code = cf_next_name(&cfp, &decl->name, "function name", "(");
- if (code == PARSE_EOF)
- goto fail;
- if (is_reserved_name(decl->name))
- err_reserved_name(&cfp, decl->name);
- code = cf_next_token_should_be(&cfp, "(", "(", NULL);
- if (code == PARSE_EOF)
- goto fail;
- parse_params(&cfp, decl);
- fail:
- success = !error_data_has_errors(&cfp.error_list);
- if (success && ret_param.type != CALL_PARAM_TYPE_VOID) {
- ret_param.name = bstrdup("return");
- da_push_back(decl->params, &ret_param);
- }
- if (!success)
- decl_info_free(decl);
- print_errors(&cfp, decl_string);
- cf_parser_free(&cfp);
- return success;
- }
|