X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=parser.c;h=f53116180c5679591dd2bc7ed52d7484367e9852;hb=4d4851e17903a5e8b66a2eef027354594e391559;hp=2dc25508449e2771220d08d5907c3f01799fb183;hpb=b1016c7f48c9d9e499351ad3a7c84db71325b81d;p=xonotic%2Fgmqcc.git diff --git a/parser.c b/parser.c index 2dc2550..f531161 100644 --- a/parser.c +++ b/parser.c @@ -476,7 +476,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) type_name[exprs[0]->vtype]); return false; } - out = (ast_expression*)ast_unary_new(ctx, (VINSTR_NEG_F-TYPE_FLOAT) + exprs[0]->vtype, exprs[0]); + if (exprs[0]->vtype == TYPE_FLOAT) + out = (ast_expression*)ast_unary_new(ctx, VINSTR_NEG_F, exprs[0]); + else + out = (ast_expression*)ast_unary_new(ctx, VINSTR_NEG_V, exprs[0]); break; case opid2('!','P'): @@ -684,12 +687,44 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid2('<','<'): case opid2('>','>'): + if (NotSameType(TYPE_FLOAT)) { + compile_error(ctx, "invalid types used in expression: cannot perform shift between types %s and %s", + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); + return false; + } + + if (!(out = fold_op(parser->fold, op, exprs))) { + ast_expression *shift = intrin_func(parser->intrin, (op->id == opid2('<','<')) ? "__builtin_lshift" : "__builtin_rshift"); + ast_call *call = ast_call_new(parser_ctx(parser), shift); + vec_push(call->params, exprs[0]); + vec_push(call->params, exprs[1]); + out = (ast_expression*)call; + } + break; + case opid3('<','<','='): case opid3('>','>','='): - if(!(out = fold_op(parser->fold, op, exprs))) { - compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-shifts"); + if (NotSameType(TYPE_FLOAT)) { + compile_error(ctx, "invalid types used in expression: cannot perform shift operation between types %s and %s", + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } + + if(!(out = fold_op(parser->fold, op, exprs))) { + ast_expression *shift = intrin_func(parser->intrin, (op->id == opid3('<','<','=')) ? "__builtin_lshift" : "__builtin_rshift"); + ast_call *call = ast_call_new(parser_ctx(parser), shift); + vec_push(call->params, exprs[0]); + vec_push(call->params, exprs[1]); + out = (ast_expression*)ast_store_new( + parser_ctx(parser), + INSTR_STORE_F, + exprs[0], + (ast_expression*)call + ); + } + break; case opid2('|','|'): @@ -1581,6 +1616,23 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) var = intrin_func(parser->intrin, parser_tokval(parser)); } + /* + * Try it again, intrin_func deals with the alias method as well + * the first one masks for __builtin though, we emit warning here. + */ + if (!var) { + if ((var = intrin_func(parser->intrin, parser_tokval(parser)))) { + (void)!compile_warning( + parser_ctx(parser), + WARN_BUILTINS, + "using implicitly defined builtin `__builtin_%s' for `%s'", + parser_tokval(parser), + parser_tokval(parser) + ); + } + } + + if (!var) { char *correct = NULL; size_t i; @@ -2810,6 +2862,14 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool * return false; } } + else if (!strcmp(parser_tokval(parser), "final")) { + flags |= AST_FLAG_FINAL_DECL; + if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) { + parseerror(parser, "`final` attribute has no parameters, expected `]]`"); + *cvq = CV_WRONG; + return false; + } + } else if (!strcmp(parser_tokval(parser), "alias") && !(flags & AST_FLAG_ALIAS)) { flags |= AST_FLAG_ALIAS; *message = NULL; @@ -2914,6 +2974,8 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool * had_var = true; else if (!strcmp(parser_tokval(parser), "noref")) had_noref = true; + else if (!strcmp(parser_tokval(parser), "final")) + flags |= AST_FLAG_FINAL_DECL; else if (!had_const && !had_var && !had_noref && !had_attrib && !had_static && !flags) { return false; } @@ -5237,6 +5299,12 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield retval = false; goto cleanup; } + if (old->flags & AST_FLAG_FINAL_DECL) { + parseerror(parser, "cannot redeclare variable `%s`, declared final here: %s:%i", + var->name, ast_ctx(old).file, ast_ctx(old).line); + retval = false; + goto cleanup; + } proto = (ast_value*)old; if (!ast_istype(old, ast_value)) { parseerror(parser, "internal error: not an ast_value"); @@ -5250,6 +5318,11 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield goto cleanup; } proto->expression.flags |= var->expression.flags; + /* copy the context for finals, + * so the error can show where it was actually made 'final' + */ + if (proto->expression.flags & AST_FLAG_FINAL_DECL) + ast_ctx(old) = ast_ctx(var); ast_delete(var); var = proto; } @@ -5421,6 +5494,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield */ char *defname = NULL; size_t prefix_len, ln; + size_t sn, sn_size; ln = strlen(parser->function->name); vec_append(defname, ln, parser->function->name); @@ -5442,6 +5516,24 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield /* now rename the global */ ln = strlen(var->name); vec_append(defname, ln, var->name); + /* if a variable of that name already existed, add the + * counter value. + * The counter is incremented either way. + */ + sn_size = vec_size(parser->function->static_names); + for (sn = 0; sn != sn_size; ++sn) { + if (strcmp(parser->function->static_names[sn], var->name) == 0) + break; + } + if (sn != sn_size) { + char *num = NULL; + int len = util_asprintf(&num, "#%u", parser->function->static_count); + vec_append(defname, len, num); + mem_d(num); + } + else + vec_push(parser->function->static_names, util_strdup(var->name)); + parser->function->static_count++; ast_value_set_name(var, defname); /* push it to the to-be-generated globals */ @@ -5692,17 +5784,18 @@ skipvar: if (!cexp) break; - if (!localblock) { + if (!localblock || is_static) { cval = (ast_value*)cexp; if (cval != parser->nil && (!ast_istype(cval, ast_value) || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield)) ) { - parseerror(parser, "cannot initialize a global constant variable with a non-constant expression"); + parseerror(parser, "initializer is non constant"); } else { - if (!OPTS_FLAG(INITIALIZED_NONCONSTANTS) && + if (!is_static && + !OPTS_FLAG(INITIALIZED_NONCONSTANTS) && qualifier != CV_VAR) { var->cvq = CV_CONST;