/*
- * Copyright (C) 2012, 2013, 2014
+ * Copyright (C) 2012, 2013, 2014, 2015
* Wolfgang Bumiller
* Dale Weiler
*
}
}
(void)check_write_to(ctx, exprs[0]);
+ /* When we're a vector of part of an entity field we use STOREP */
+ if (ast_istype(exprs[0], ast_member) && ast_istype(((ast_member*)exprs[0])->owner, ast_entfield))
+ assignop = INSTR_STOREP_F;
out = (ast_expression*)ast_store_new(ctx, assignop, exprs[0], exprs[1]);
break;
case opid3('+','+','P'):
out = (ast_expression*)asbinstore;
break;
+ case opid3('l', 'e', 'n'):
+ if (exprs[0]->vtype != TYPE_STRING && exprs[0]->vtype != TYPE_ARRAY) {
+ ast_type_to_string(exprs[0], ty1, sizeof(ty1));
+ compile_error(ast_ctx(exprs[0]), "invalid type for length operator: %s", ty1);
+ return false;
+ }
+ /* strings must be const, arrays are statically sized */
+ if (exprs[0]->vtype == TYPE_STRING &&
+ !(((ast_value*)exprs[0])->hasvalue && ((ast_value*)exprs[0])->cvq == CV_CONST))
+ {
+ compile_error(ast_ctx(exprs[0]), "operand of length operator not a valid constant expression");
+ return false;
+ }
+ out = fold_op(parser->fold, op, exprs);
+ break;
+
case opid2('~', 'P'):
if (exprs[0]->vtype != TYPE_FLOAT && exprs[0]->vtype != TYPE_VECTOR) {
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
if ((fun->flags & AST_FLAG_VARIADIC) &&
!(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin))
{
- call->va_count = (ast_expression*)fold_constgen_float(parser->fold, (qcfloat_t)paramcount);
+ call->va_count = (ast_expression*)fold_constgen_float(parser->fold, (qcfloat_t)paramcount, false);
}
}
return true;
}
else if (parser->tok == TOKEN_FLOATCONST) {
- ast_expression *val = fold_constgen_float(parser->fold, (parser_token(parser)->constval.f));
+ ast_expression *val = fold_constgen_float(parser->fold, (parser_token(parser)->constval.f), false);
if (!val)
return false;
vec_push(sy->out, syexp(parser_ctx(parser), val));
return true;
}
else if (parser->tok == TOKEN_INTCONST || parser->tok == TOKEN_CHARCONST) {
- ast_expression *val = fold_constgen_float(parser->fold, (qcfloat_t)(parser_token(parser)->constval.i));
+ ast_expression *val = fold_constgen_float(parser->fold, (qcfloat_t)(parser_token(parser)->constval.i), false);
if (!val)
return false;
vec_push(sy->out, syexp(parser_ctx(parser), val));
if (!var) {
- char *correct = NULL;
- size_t i;
-
/*
* sometimes people use preprocessing predefs without enabling them
* i've done this thousands of times already myself. Lets check for
return false;
}
- /*
- * TODO: determine the best score for the identifier: be it
- * a variable, a field.
- *
- * We should also consider adding correction tables for
- * other things as well.
- */
- if (OPTS_OPTION_BOOL(OPTION_CORRECTION) && strlen(parser_tokval(parser)) <= 16) {
- correction_t corr;
- correct_init(&corr);
-
- for (i = 0; i < vec_size(parser->correct_variables); i++) {
- correct = correct_str(&corr, parser->correct_variables[i], parser_tokval(parser));
- if (strcmp(correct, parser_tokval(parser))) {
- break;
- } else {
- mem_d(correct);
- correct = NULL;
- }
- }
- correct_free(&corr);
-
- if (correct) {
- parseerror(parser, "unexpected identifier: %s (did you mean %s?)", parser_tokval(parser), correct);
- mem_d(correct);
- return false;
- }
- }
parseerror(parser, "unexpected identifier: %s", parser_tokval(parser));
return false;
}
vec_push(parser->typedefs, util_htnew(TYPEDEF_HT_SIZE));
vec_push(parser->_blocktypedefs, vec_size(parser->_typedefs));
vec_push(parser->_block_ctx, parser_ctx(parser));
-
- /* corrector */
- vec_push(parser->correct_variables, correct_trie_new());
- vec_push(parser->correct_variables_score, NULL);
}
static bool parser_leaveblock(parser_t *parser)
}
util_htdel(vec_last(parser->variables));
- correct_del(vec_last(parser->correct_variables), vec_last(parser->correct_variables_score));
vec_pop(parser->variables);
- vec_pop(parser->correct_variables);
- vec_pop(parser->correct_variables_score);
if (!vec_size(parser->_blocklocals)) {
parseerror(parser, "internal error: parser_leaveblock with no block (2)");
return false;
{
vec_push(parser->_locals, e);
util_htset(vec_last(parser->variables), name, (void*)e);
-
- /* corrector */
- correct_add (
- vec_last(parser->correct_variables),
- &vec_last(parser->correct_variables_score),
- name
- );
}
static void parser_addglobal(parser_t *parser, const char *name, ast_expression *e)
{
vec_push(parser->globals, e);
util_htset(parser->htglobals, name, e);
-
- /* corrector */
- correct_add (
- parser->correct_variables[0],
- &parser->correct_variables_score[0],
- name
- );
}
static ast_expression* process_condition(parser_t *parser, ast_expression *cond, bool *_ifnot)
initexpr = parse_expression_leave(parser, false, false, false);
if (!initexpr)
goto onerr;
- }
- /* move on to condition */
- if (parser->tok != ';') {
- parseerror(parser, "expected semicolon after for-loop initializer");
- goto onerr;
- }
- if (!parser_next(parser)) {
- parseerror(parser, "expected for-loop condition");
- goto onerr;
+ /* move on to condition */
+ if (parser->tok != ';') {
+ parseerror(parser, "expected semicolon after for-loop initializer");
+ goto onerr;
+ }
+
+ if (!parser_next(parser)) {
+ parseerror(parser, "expected for-loop condition");
+ goto onerr;
+ }
}
/* parse the condition */
if (parser->tok == TOKEN_IDENT)
typevar = parser_find_typedef(parser, parser_tokval(parser), 0);
if (typevar || parser->tok == TOKEN_TYPENAME) {
- if (!parse_variable(parser, block, false, CV_NONE, typevar, false, false, 0, NULL)) {
+ if (!parse_variable(parser, block, true, CV_NONE, typevar, false, false, 0, NULL)) {
ast_delete(switchnode);
return false;
}
ast_delete(switchnode);
return false;
}
- if (!parse_variable(parser, block, false, cvq, NULL, noref, is_static, qflags, NULL)) {
+ if (!parse_variable(parser, block, true, cvq, NULL, noref, is_static, qflags, NULL)) {
ast_delete(switchnode);
return false;
}
{
if (cvq == CV_WRONG)
return false;
- return parse_variable(parser, block, true, cvq, NULL, noref, is_static, qflags, vstring);
+ return parse_variable(parser, block, false, cvq, NULL, noref, is_static, qflags, vstring);
}
else if (parser->tok == TOKEN_KEYWORD)
{
self_think = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_think);
time_plus_1 = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F,
- gbl_time, (ast_expression*)fold_constgen_float(parser->fold, frame_delta));
+ gbl_time, (ast_expression*)fold_constgen_float(parser->fold, frame_delta, false));
if (!self_frame || !self_nextthink || !self_think || !time_plus_1) {
if (self_frame) ast_delete(self_frame);
goto enderrfn;
}
func->varargs = varargs;
- func->fixedparams = (ast_value*)fold_constgen_float(parser->fold, vec_size(var->expression.params));
+ func->fixedparams = (ast_value*)fold_constgen_float(parser->fold, vec_size(var->expression.params), false);
}
parser->function = func;
cmp = ast_binary_new(ctx, INSTR_LT,
(ast_expression*)index,
- (ast_expression*)fold_constgen_float(parser->fold, middle));
+ (ast_expression*)fold_constgen_float(parser->fold, middle, false));
if (!cmp) {
ast_delete(left);
ast_delete(right);
if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR)
assignop = INSTR_STORE_V;
- subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from));
+ subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from, false));
if (!subscript)
return NULL;
if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR)
assignop = INSTR_STOREP_V;
- subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from));
+ subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from, false));
if (!subscript)
return NULL;
ast_return *ret;
ast_array_index *subscript;
- subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from));
+ subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from, false));
if (!subscript)
return NULL;
}
if (parser->tok == TOKEN_IDENT) {
argcounter = util_strdup(parser_tokval(parser));
+ ast_value_set_name(param, argcounter);
if (!parser_next(parser) || parser->tok != ')') {
parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
goto on_error;
}
}
}
+ if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC && param->name[0] == '<') {
+ parseerror(parser, "parameter name omitted");
+ goto on_error;
+ }
}
}
bool wasarray = false;
ast_member *me[3] = { NULL, NULL, NULL };
+ ast_member *last_me[3] = { NULL, NULL, NULL };
if (!localblock && is_static)
parseerror(parser, "`static` qualifier is not supported in global scope");
return false;
}
- /*
- * add alias to aliases table and to corrector
- * so corrections can apply for aliases as well.
- */
util_htset(parser->aliases, var->name, find);
- /*
- * add to corrector so corrections can work
- * even for aliases too.
- */
- correct_add (
- vec_last(parser->correct_variables),
- &vec_last(parser->correct_variables_score),
- var->name
- );
-
/* generate aliases for vector components */
if (isvector) {
char *buffer[3];
mem_d(buffer[0]);
mem_d(buffer[1]);
mem_d(buffer[2]);
-
- /*
- * add to corrector so corrections can work
- * even for aliases too.
- */
- correct_add (
- vec_last(parser->correct_variables),
- &vec_last(parser->correct_variables_score),
- me[0]->name
- );
- correct_add (
- vec_last(parser->correct_variables),
- &vec_last(parser->correct_variables_score),
- me[1]->name
- );
- correct_add (
- vec_last(parser->correct_variables),
- &vec_last(parser->correct_variables_score),
- me[2]->name
- );
}
}
}
/* Add it to the local scope */
util_htset(vec_last(parser->variables), var->name, (void*)var);
- /* corrector */
- correct_add (
- vec_last(parser->correct_variables),
- &vec_last(parser->correct_variables_score),
- var->name
- );
-
/* now rename the global */
ln = strlen(var->name);
vec_append(defname, ln, var->name);
for (i = 0; i < 3; ++i) {
util_htset(vec_last(parser->variables), me[i]->name, (void*)(me[i]));
- /* corrector */
- correct_add(
- vec_last(parser->correct_variables),
- &vec_last(parser->correct_variables_score),
- me[i]->name
- );
-
vec_shrinkto(defname, prefix_len);
ln = strlen(me[i]->name);
vec_append(defname, ln, me[i]->name);
}
}
}
+ memcpy(last_me, me, sizeof(me));
me[0] = me[1] = me[2] = NULL;
cleanvar = false;
/* Part 2.2
} else {
ast_expression *cexp;
ast_value *cval;
+ bool folded_const = false;
cexp = parse_expression_leave(parser, true, false, false);
if (!cexp)
break;
+ cval = ast_istype(cexp, ast_value) ? (ast_value*)cexp : NULL;
+
+ /* deal with foldable constants: */
+ if (localblock &&
+ var->cvq == CV_CONST && cval && cval->hasvalue && cval->cvq == CV_CONST && !cval->isfield)
+ {
+ /* remove it from the current locals */
+ if (isvector) {
+ for (i = 0; i < 3; ++i) {
+ vec_pop(parser->_locals);
+ vec_pop(localblock->collect);
+ }
+ }
+ /* do sanity checking, this function really needs refactoring */
+ if (vec_last(parser->_locals) != (ast_expression*)var)
+ parseerror(parser, "internal error: unexpected change in local variable handling");
+ else
+ vec_pop(parser->_locals);
+ if (vec_last(localblock->locals) != var)
+ parseerror(parser, "internal error: unexpected change in local variable handling (2)");
+ else
+ vec_pop(localblock->locals);
+ /* push it to the to-be-generated globals */
+ vec_push(parser->globals, (ast_expression*)var);
+ if (isvector)
+ for (i = 0; i < 3; ++i)
+ vec_push(parser->globals, (ast_expression*)last_me[i]);
+ folded_const = true;
+ }
- if (!localblock || is_static) {
- cval = (ast_value*)cexp;
+ if (folded_const || !localblock || is_static) {
if (cval != parser->nil &&
- (!ast_istype(cval, ast_value) || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield))
+ (!cval || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield))
)
{
parseerror(parser, "initializer is non constant");
vec_free(sy.argc);
var->cvq = cvq;
}
+ /* a constant initialized to an inexact value should be marked inexact:
+ * const float x = <inexact>; should propagate the inexact flag
+ */
+ if (var->cvq == CV_CONST && var->expression.vtype == TYPE_FLOAT) {
+ if (cval && cval->hasvalue && cval->cvq == CV_CONST)
+ var->inexact = cval->inexact;
+ }
}
another:
{
if (cvq == CV_WRONG)
return false;
- return parse_variable(parser, NULL, true, cvq, NULL, noref, is_static, qflags, vstring);
+ return parse_variable(parser, NULL, false, cvq, NULL, noref, is_static, qflags, vstring);
}
else if (parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "enum"))
{
parser->aliases = util_htnew(PARSER_HT_SIZE);
- /* corrector */
- vec_push(parser->correct_variables, correct_trie_new());
- vec_push(parser->correct_variables_score, NULL);
-
empty_ctx.file = "<internal>";
empty_ctx.line = 0;
empty_ctx.column = 0;
vec_free(parser->_blocklocals);
vec_free(parser->_locals);
- /* corrector */
- for (i = 0; i < vec_size(parser->correct_variables); ++i) {
- correct_del(parser->correct_variables[i], parser->correct_variables_score[i]);
- }
- vec_free(parser->correct_variables);
- vec_free(parser->correct_variables_score);
-
for (i = 0; i < vec_size(parser->_typedefs); ++i)
ast_delete(parser->_typedefs[i]);
vec_free(parser->_typedefs);