size_t *_blocklocals;
ast_value **_typedefs;
size_t *_blocktypedefs;
+ lex_ctx *_block_ctx;
size_t errors;
qcint memberof;
} parser_t;
-#define CV_NONE 0
-#define CV_CONST 1
-#define CV_VAR -1
-
static void parser_enterblock(parser_t *parser);
static bool parser_leaveblock(parser_t *parser);
static void parser_addlocal(parser_t *parser, const char *name, ast_expression *e);
static bool parse_typedef(parser_t *parser);
-static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int is_const_var, ast_value *cached_typedef);
-static ast_block* parse_block(parser_t *parser, bool warnreturn);
-static bool parse_block_into(parser_t *parser, ast_block *block, bool warnreturn);
+static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef);
+static ast_block* parse_block(parser_t *parser);
+static bool parse_block_into(parser_t *parser, ast_block *block);
static ast_expression* parse_statement_or_block(parser_t *parser);
static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out, bool allow_cases);
static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma);
return parser->imm_float[i];
}
out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_FLOAT);
- out->constant = true;
+ out->cvq = CV_CONST;
out->hasvalue = true;
out->constval.vfloat = d;
vec_push(parser->imm_float, out);
out = ast_value_new(parser_ctx(parser), name, TYPE_STRING);
} else
out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING);
- out->constant = true;
+ out->cvq = CV_CONST;
out->hasvalue = true;
out->constval.vstring = parser_strdup(str);
vec_push(parser->imm_string, out);
return parser->imm_vector[i];
}
out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_VECTOR);
- out->constant = true;
+ out->cvq = CV_CONST;
out->hasvalue = true;
out->constval.vvec = v;
vec_push(parser->imm_vector, out);
(exprs[0]->expression.vtype != exprs[1]->expression.vtype || \
exprs[0]->expression.vtype != T)
#define CanConstFold1(A) \
- (ast_istype((A), ast_value) && ((ast_value*)(A))->hasvalue && ((ast_value*)(A))->constant)
+ (ast_istype((A), ast_value) && ((ast_value*)(A))->hasvalue && (((ast_value*)(A))->cvq == CV_CONST))
#define CanConstFold(A, B) \
(CanConstFold1(A) && CanConstFold1(B))
#define ConstV(i) (asvalue[(i)]->constval.vvec)
out = (ast_expression*)ast_array_index_new(ctx, exprs[0], exprs[1]);
if (rotate_entfield_array_index_nodes(&out))
{
+#if 0
+ /* This is not broken in fteqcc anymore */
if (opts_standard != COMPILER_GMQCC) {
/* this error doesn't need to make us bail out */
(void)!parsewarning(parser, WARN_EXTENSIONS,
"accessing array-field members of an entity without parenthesis\n"
" -> this is an extension from -std=gmqcc");
}
+#endif
}
break;
if (exprs[1]->expression.vtype != exprs[2]->expression.vtype) {
ast_type_to_string(exprs[1], ty1, sizeof(ty1));
ast_type_to_string(exprs[2], ty2, sizeof(ty2));
- parseerror(parser, "iperands of ternary expression must have the same type, got %s and %s", ty1, ty2);
+ parseerror(parser, "operands of ternary expression must have the same type, got %s and %s", ty1, ty2);
return false;
}
if (CanConstFold1(exprs[0]))
parseerror(parser, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
}
}
- if (ast_istype(exprs[0], ast_value) && asvalue[0]->constant) {
+ if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
}
out = (ast_expression*)ast_store_new(ctx, assignop, exprs[0], exprs[1]);
addop = INSTR_ADD_F;
else
addop = INSTR_SUB_F;
- if (ast_istype(exprs[0], ast_value) && asvalue[0]->constant) {
+ if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
}
if (ast_istype(exprs[0], ast_entfield)) {
addop = INSTR_SUB_F;
subop = INSTR_ADD_F;
}
- if (ast_istype(exprs[0], ast_value) && asvalue[0]->constant) {
+ if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
}
if (ast_istype(exprs[0], ast_entfield)) {
ty1, ty2);
return false;
}
- if (ast_istype(exprs[0], ast_value) && asvalue[0]->constant) {
+ if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
}
if (ast_istype(exprs[0], ast_entfield))
ty1, ty2);
return false;
}
- if (ast_istype(exprs[0], ast_value) && asvalue[0]->constant) {
+ if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
}
if (ast_istype(exprs[0], ast_entfield))
ty1, ty2);
return false;
}
- if (ast_istype(exprs[0], ast_value) && asvalue[0]->constant) {
+ if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
}
if (ast_istype(exprs[0], ast_entfield))
out = (ast_expression*)ast_binary_new(ctx, INSTR_BITAND, exprs[0], exprs[1]);
if (!out)
return false;
- if (ast_istype(exprs[0], ast_value) && asvalue[0]->constant) {
+ if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
}
asbinstore = ast_binstore_new(ctx, assignop, INSTR_SUB_F, exprs[0], out);
parseerror(parser, "unexpected ident: %s", parser_tokval(parser));
goto onerr;
}
- if (ast_istype(var, ast_value))
+ if (ast_istype(var, ast_value)) {
((ast_value*)var)->uses++;
+ }
+ else if (ast_istype(var, ast_member)) {
+ ast_member *mem = (ast_member*)var;
+ if (ast_istype(mem->owner, ast_value))
+ ((ast_value*)(mem->owner))->uses++;
+ }
vec_push(sy.out, syexp(parser_ctx(parser), var));
DEBUGSHUNTDO(con_out("push %s\n", parser_tokval(parser)));
}
vec_push(parser->_blocklocals, vec_size(parser->_locals));
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));
}
static bool parser_leaveblock(parser_t *parser)
ast_value *v = (ast_value*)e;
vec_pop(parser->_locals);
if (ast_istype(e, ast_value) && !v->uses) {
- if (parsewarning(parser, WARN_UNUSED_VARIABLE, "unused variable: `%s`", v->name))
+ if (compile_warning(ast_ctx(v), WARN_UNUSED_VARIABLE, "unused variable: `%s`", v->name)) {
+ parser->errors++;
rv = false;
+ }
}
}
util_htdel(vec_last(parser->typedefs));
vec_pop(parser->typedefs);
+ vec_pop(parser->_block_ctx);
return rv;
}
ast_return *ret = NULL;
ast_value *expected = parser->function->vtype;
+ lex_ctx ctx = parser_ctx(parser);
+
(void)block; /* not touching */
if (!parser_next(parser)) {
else
parseerror(parser, "return without value");
}
- ret = ast_return_new(parser_ctx(parser), NULL);
+ ret = ast_return_new(ctx, NULL);
}
*out = (ast_expression*)ret;
return true;
}
if (!OPTS_FLAG(RELAXED_SWITCH)) {
opval = (ast_value*)swcase.value;
- if (!ast_istype(swcase.value, ast_value)) { /* || !opval->constant) { */
+ if (!ast_istype(swcase.value, ast_value)) { /* || opval->cvq != CV_CONST) { */
parseerror(parser, "case on non-constant values need to be explicitly enabled via -frelaxed-switch");
ast_unref(operand);
return false;
else if (parser->tok == '{')
{
ast_block *inner;
- inner = parse_block(parser, false);
+ inner = parse_block(parser);
if (!inner)
return false;
*out = (ast_expression*)inner;
}
}
-static bool parse_block_into(parser_t *parser, ast_block *block, bool warnreturn)
+static bool parse_block_into(parser_t *parser, ast_block *block)
{
bool retval = true;
if (parser->tok != '}') {
block = NULL;
} else {
- if (warnreturn && parser->function->vtype->expression.next->expression.vtype != TYPE_VOID)
- {
- if (!vec_size(block->exprs) ||
- !ast_istype(vec_last(block->exprs), ast_return))
- {
- if (parsewarning(parser, WARN_MISSING_RETURN_VALUES, "control reaches end of non-void function")) {
- block = NULL;
- goto cleanup;
- }
- }
- }
(void)parser_next(parser);
}
return retval && !!block;
}
-static ast_block* parse_block(parser_t *parser, bool warnreturn)
+static ast_block* parse_block(parser_t *parser)
{
ast_block *block;
block = ast_block_new(parser_ctx(parser));
if (!block)
return NULL;
- if (!parse_block_into(parser, block, warnreturn)) {
+ if (!parse_block_into(parser, block)) {
ast_block_delete(block);
return NULL;
}
{
ast_expression *expr = NULL;
if (parser->tok == '{')
- return (ast_expression*)parse_block(parser, false);
+ return (ast_expression*)parse_block(parser);
if (!parse_statement(parser, NULL, &expr, false))
return NULL;
return expr;
vec_push(parser->functions, func);
parser->function = func;
- if (!parse_block_into(parser, block, true)) {
+ if (!parse_block_into(parser, block)) {
ast_block_delete(block);
goto enderrfn;
}
return true;
}
-static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int is_const_var, ast_value *cached_typedef)
+static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef)
{
ast_value *var;
ast_value *proto;
}
}
- if (is_const_var == CV_CONST)
- var->constant = true;
+ var->cvq = qualifier;
/* Part 1:
* check for validity: (end_sys_..., multiple-definitions, prototypes, ...)
if (!localblock) {
/* deal with global variables, fields, functions */
- if (!nofields && var->expression.vtype == TYPE_FIELD) {
+ if (!nofields && var->expression.vtype == TYPE_FIELD && parser->tok != '=') {
+ var->isfield = true;
vec_push(parser->fields, (ast_expression*)var);
util_htset(parser->htfields, var->name, var);
if (isvector) {
if (parser->tok == ',')
goto another;
+ /*
if (!var || (!localblock && !nofields && basetype->expression.vtype == TYPE_FIELD)) {
+ */
+ if (!var) {
parseerror(parser, "missing comma or semicolon while parsing variables");
break;
}
break;
}
+ if (proto)
+ ast_ctx(proto) = parser_ctx(parser);
+
if (!parse_function_body(parser, var))
break;
ast_delete(basetype);
if (!localblock) {
cval = (ast_value*)cexp;
- if (!ast_istype(cval, ast_value) || !cval->hasvalue || !cval->constant)
+ if (!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");
else
{
if (opts_standard != COMPILER_GMQCC &&
!OPTS_FLAG(INITIALIZED_NONCONSTANTS) &&
- is_const_var != CV_VAR)
+ qualifier != CV_VAR)
{
- var->constant = true;
+ var->cvq = CV_CONST;
}
var->hasvalue = true;
if (cval->expression.vtype == TYPE_STRING)
var->constval.vstring = parser_strdup(cval->constval.vstring);
+ else if (cval->expression.vtype == TYPE_FIELD)
+ var->constval.vfield = cval;
else
memcpy(&var->constval, &cval->constval, sizeof(var->constval));
ast_unref(cval);
} else {
bool cvq;
shunt sy = { NULL, NULL };
- cvq = var->constant;
- var->constant = false;
+ cvq = var->cvq;
+ var->cvq = CV_NONE;
vec_push(sy.out, syexp(ast_ctx(var), (ast_expression*)var));
vec_push(sy.out, syexp(ast_ctx(cexp), (ast_expression*)cexp));
vec_push(sy.ops, syop(ast_ctx(var), parser->assign_op));
}
vec_free(sy.out);
vec_free(sy.ops);
- var->constant = cvq;
+ var->cvq = cvq;
}
}
vec_free(parser->typedefs);
vec_free(parser->_blocktypedefs);
+ vec_free(parser->_block_ctx);
+
vec_free(parser->labels);
vec_free(parser->gotos);