/* beginning of locals */
#define PARSER_HT_LOCALS 2
-#define PARSER_HT_SIZE 1024
+#define PARSER_HT_SIZE 128
#define TYPEDEF_HT_SIZE 16
enum parser_pot { POT_PAREN, POT_TERNARY1, POT_TERNARY2 };
/* pragma flags */
bool noref;
+
+ /* collected information */
+ size_t max_param_count;
} parser_t;
-static const ast_expression *intrinsic_debug_typestring = (ast_expression*)0x10;
+static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1;
static void parser_enterblock(parser_t *parser);
static bool parser_leaveblock(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, bool truthvalue, bool with_labels);
static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels);
+static ast_value* parser_create_array_setter_proto(parser_t *parser, ast_value *array, const char *funcname);
+static ast_value* parser_create_array_getter_proto(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname);
+static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef);
static void parseerror(parser_t *parser, const char *fmt, ...)
{
{
size_t i;
ast_value *out;
+ lex_ctx ctx;
for (i = 0; i < vec_size(parser->imm_float); ++i) {
const double compare = parser->imm_float[i]->constval.vfloat;
if (memcmp((const void*)&compare, (const void *)&d, sizeof(double)) == 0)
return parser->imm_float[i];
}
- out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_FLOAT);
+ if (parser->lex)
+ ctx = parser_ctx(parser);
+ else {
+ memset(&ctx, 0, sizeof(ctx));
+ }
+ out = ast_value_new(ctx, "#IMMEDIATE", TYPE_FLOAT);
out->cvq = CV_CONST;
out->hasvalue = true;
out->constval.vfloat = d;
DEBUGSHUNTDO(con_out("apply %s\n", op->op));
if (vec_size(sy->out) < op->operands) {
- parseerror(parser, "internal error: not enough operands: %i (operator %s (%i))", vec_size(sy->out),
- op->op, (int)op->id);
+ compile_error(ctx, "internal error: not enough operands: %i (operator %s (%i))", vec_size(sy->out),
+ op->op, (int)op->id);
return false;
}
}
if (blocks[0] && !vec_size(blocks[0]->exprs) && op->id != opid1(',')) {
- parseerror(parser, "internal error: operator cannot be applied on empty blocks");
+ compile_error(ctx, "internal error: operator cannot be applied on empty blocks");
return false;
}
switch (op->id)
{
default:
- parseerror(parser, "internal error: unhandled operator: %s (%i)", op->op, (int)op->id);
+ compile_error(ctx, "internal error: unhandled operator: %s (%i)", op->op, (int)op->id);
return false;
case opid1('.'):
else if (exprs[1] == (ast_expression*)parser->const_vec[2])
out = (ast_expression*)ast_member_new(ctx, exprs[0], 2, NULL);
else {
- parseerror(parser, "access to invalid vector component");
+ compile_error(ctx, "access to invalid vector component");
return false;
}
}
else if (exprs[0]->expression.vtype == TYPE_ENTITY) {
if (exprs[1]->expression.vtype != TYPE_FIELD) {
- parseerror(parser, "type error: right hand of member-operand should be an entity-field");
+ compile_error(ast_ctx(exprs[1]), "type error: right hand of member-operand should be an entity-field");
return false;
}
out = (ast_expression*)ast_entfield_new(ctx, exprs[0], exprs[1]);
}
else if (exprs[0]->expression.vtype == TYPE_VECTOR) {
- parseerror(parser, "vectors cannot be accessed this way");
+ compile_error(ast_ctx(exprs[1]), "vectors cannot be accessed this way");
return false;
}
else {
- parseerror(parser, "type error: member-of operator on something that is not an entity or vector");
+ compile_error(ast_ctx(exprs[1]), "type error: member-of operator on something that is not an entity or vector");
return false;
}
break;
exprs[0]->expression.next->expression.vtype == TYPE_ARRAY))
{
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
- parseerror(parser, "cannot index value of type %s", ty1);
+ compile_error(ast_ctx(exprs[0]), "cannot index value of type %s", ty1);
return false;
}
if (exprs[1]->expression.vtype != TYPE_FLOAT) {
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
- parseerror(parser, "index must be of type float, not %s", ty1);
+ compile_error(ast_ctx(exprs[1]), "index must be of type float, not %s", ty1);
return false;
}
out = (ast_expression*)ast_array_index_new(ctx, exprs[0], exprs[1]);
exprs[0]);
break;
default:
- parseerror(parser, "invalid types used in expression: cannot negate type %s",
- type_name[exprs[0]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot negate type %s",
+ type_name[exprs[0]->expression.vtype]);
return false;
}
break;
out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_FNC, exprs[0]);
break;
default:
- parseerror(parser, "invalid types used in expression: cannot logically negate type %s",
- type_name[exprs[0]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot logically negate type %s",
+ type_name[exprs[0]->expression.vtype]);
return false;
}
break;
if (exprs[0]->expression.vtype != exprs[1]->expression.vtype ||
(exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) )
{
- parseerror(parser, "invalid types used in expression: cannot add type %s and %s",
- type_name[exprs[0]->expression.vtype],
- type_name[exprs[1]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot add type %s and %s",
+ type_name[exprs[0]->expression.vtype],
+ type_name[exprs[1]->expression.vtype]);
return false;
}
switch (exprs[0]->expression.vtype) {
out = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_V, exprs[0], exprs[1]);
break;
default:
- parseerror(parser, "invalid types used in expression: cannot add type %s and %s",
- type_name[exprs[0]->expression.vtype],
- type_name[exprs[1]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot add type %s and %s",
+ type_name[exprs[0]->expression.vtype],
+ type_name[exprs[1]->expression.vtype]);
return false;
};
break;
if (exprs[0]->expression.vtype != exprs[1]->expression.vtype ||
(exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) )
{
- parseerror(parser, "invalid types used in expression: cannot subtract type %s from %s",
- type_name[exprs[1]->expression.vtype],
- type_name[exprs[0]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s",
+ type_name[exprs[1]->expression.vtype],
+ type_name[exprs[0]->expression.vtype]);
return false;
}
switch (exprs[0]->expression.vtype) {
out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, exprs[0], exprs[1]);
break;
default:
- parseerror(parser, "invalid types used in expression: cannot subtract type %s from %s",
- type_name[exprs[1]->expression.vtype],
- type_name[exprs[0]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s",
+ type_name[exprs[1]->expression.vtype],
+ type_name[exprs[0]->expression.vtype]);
return false;
};
break;
exprs[0]->expression.vtype == TYPE_FLOAT)
)
{
- parseerror(parser, "invalid types used in expression: cannot multiply types %s and %s",
- type_name[exprs[1]->expression.vtype],
- type_name[exprs[0]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s",
+ type_name[exprs[1]->expression.vtype],
+ type_name[exprs[0]->expression.vtype]);
return false;
}
switch (exprs[0]->expression.vtype) {
}
break;
default:
- parseerror(parser, "invalid types used in expression: cannot multiply types %s and %s",
- type_name[exprs[1]->expression.vtype],
- type_name[exprs[0]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s",
+ type_name[exprs[1]->expression.vtype],
+ type_name[exprs[0]->expression.vtype]);
return false;
};
break;
case opid1('/'):
- if (NotSameType(TYPE_FLOAT)) {
- parseerror(parser, "invalid types used in expression: cannot divide types %s and %s",
- type_name[exprs[0]->expression.vtype],
- type_name[exprs[1]->expression.vtype]);
+ if (exprs[1]->expression.vtype != TYPE_FLOAT) {
+ ast_type_to_string(exprs[0], ty1, sizeof(ty1));
+ ast_type_to_string(exprs[1], ty2, sizeof(ty2));
+ compile_error(ctx, "invalid types used in expression: cannot divide tyeps %s and %s", ty1, ty2);
return false;
}
- if (CanConstFold(exprs[0], exprs[1]))
- out = (ast_expression*)parser_const_float(parser, ConstF(0) / ConstF(1));
+ if (exprs[0]->expression.vtype == TYPE_FLOAT) {
+ if (CanConstFold(exprs[0], exprs[1]))
+ out = (ast_expression*)parser_const_float(parser, ConstF(0) / ConstF(1));
+ else
+ out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]);
+ }
+ else if (exprs[0]->expression.vtype == TYPE_VECTOR) {
+ if (CanConstFold(exprs[0], exprs[1]))
+ out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(0), 1.0/ConstF(1)));
+ else {
+ if (CanConstFold1(exprs[1])) {
+ out = (ast_expression*)parser_const_float(parser, 1.0 / ConstF(1));
+ } else {
+ out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F,
+ (ast_expression*)parser_const_float_1(parser),
+ exprs[1]);
+ }
+ if (!out) {
+ compile_error(ctx, "internal error: failed to generate division");
+ return false;
+ }
+ out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_VF, exprs[0], out);
+ }
+ }
else
- out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]);
+ {
+ ast_type_to_string(exprs[0], ty1, sizeof(ty1));
+ ast_type_to_string(exprs[1], ty2, sizeof(ty2));
+ compile_error(ctx, "invalid types used in expression: cannot divide tyeps %s and %s", ty1, ty2);
+ return false;
+ }
break;
case opid1('%'):
case opid2('%','='):
- parseerror(parser, "qc does not have a modulo operator");
+ compile_error(ctx, "qc does not have a modulo operator");
return false;
case opid1('|'):
case opid1('&'):
if (NotSameType(TYPE_FLOAT)) {
- parseerror(parser, "invalid types used in expression: cannot perform bit operations between types %s and %s",
- type_name[exprs[0]->expression.vtype],
- type_name[exprs[1]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot perform bit operations between types %s and %s",
+ type_name[exprs[0]->expression.vtype],
+ type_name[exprs[1]->expression.vtype]);
return false;
}
if (CanConstFold(exprs[0], exprs[1]))
generated_op += 1; /* INSTR_OR */
case opid2('&','&'):
generated_op += INSTR_AND;
-#if 0
- if (NotSameType(TYPE_FLOAT)) {
- parseerror(parser, "invalid types used in expression: cannot perform logical operations between types %s and %s",
- type_name[exprs[0]->expression.vtype],
- type_name[exprs[1]->expression.vtype]);
- parseerror(parser, "TODO: logical ops for arbitrary types using INSTR_NOT");
- parseerror(parser, "TODO: optional early out");
- return false;
- }
-#endif
if (CanConstFold(exprs[0], exprs[1]))
{
if (OPTS_FLAG(PERL_LOGIC)) {
if (OPTS_FLAG(PERL_LOGIC) && !ast_compare_type(exprs[0], exprs[1])) {
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
ast_type_to_string(exprs[1], ty2, sizeof(ty2));
- parseerror(parser, "invalid types for logical operation with -fperl-logic: %s and %s", ty1, ty2);
+ compile_error(ctx, "invalid types for logical operation with -fperl-logic: %s and %s", ty1, ty2);
return false;
}
for (i = 0; i < 2; ++i) {
case opid2('?',':'):
if (vec_last(parser->pot) != POT_TERNARY2) {
- parseerror(parser, "mismatched parenthesis/ternary");
+ compile_error(ctx, "mismatched parenthesis/ternary");
return false;
}
vec_pop(parser->pot);
if (!ast_compare_type(exprs[1], exprs[2])) {
ast_type_to_string(exprs[1], ty1, sizeof(ty1));
ast_type_to_string(exprs[2], ty2, sizeof(ty2));
- parseerror(parser, "operands of ternary expression must have the same type, got %s and %s", ty1, ty2);
+ compile_error(ctx, "operands of ternary expression must have the same type, got %s and %s", ty1, ty2);
return false;
}
if (CanConstFold1(exprs[0]))
case opid2('<', '='):
generated_op += INSTR_LE;
if (NotSameType(TYPE_FLOAT)) {
- parseerror(parser, "invalid types used in expression: cannot perform comparison between types %s and %s",
- type_name[exprs[0]->expression.vtype],
- type_name[exprs[1]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s",
+ type_name[exprs[0]->expression.vtype],
+ type_name[exprs[1]->expression.vtype]);
return false;
}
out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]);
break;
case opid2('!', '='):
if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) {
- parseerror(parser, "invalid types used in expression: cannot perform comparison between types %s and %s",
- type_name[exprs[0]->expression.vtype],
- type_name[exprs[1]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s",
+ type_name[exprs[0]->expression.vtype],
+ type_name[exprs[1]->expression.vtype]);
return false;
}
out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->expression.vtype], exprs[0], exprs[1]);
break;
case opid2('=', '='):
if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) {
- parseerror(parser, "invalid types used in expression: cannot perform comparison between types %s and %s",
- type_name[exprs[0]->expression.vtype],
- type_name[exprs[1]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s",
+ type_name[exprs[0]->expression.vtype],
+ type_name[exprs[1]->expression.vtype]);
return false;
}
out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->expression.vtype], exprs[0], exprs[1]);
field->expression.next->expression.vtype == TYPE_FUNCTION &&
exprs[1]->expression.vtype == TYPE_FUNCTION)
{
- (void)!parsewarning(parser, WARN_ASSIGN_FUNCTION_TYPES,
- "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
+ (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES,
+ "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
}
else
- parseerror(parser, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
+ compile_error(ctx, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
}
}
else
if (assignop == AINSTR_END) {
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
ast_type_to_string(exprs[1], ty2, sizeof(ty2));
- parseerror(parser, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
+ compile_error(ctx, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
}
else if (!ast_compare_type(exprs[0], exprs[1]))
{
exprs[0]->expression.vtype == TYPE_FUNCTION &&
exprs[1]->expression.vtype == TYPE_FUNCTION)
{
- (void)!parsewarning(parser, WARN_ASSIGN_FUNCTION_TYPES,
- "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
+ (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES,
+ "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
}
else
- parseerror(parser, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
+ compile_error(ctx, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
}
}
if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
- parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
+ compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name);
}
out = (ast_expression*)ast_store_new(ctx, assignop, exprs[0], exprs[1]);
break;
/* prefix ++ */
if (exprs[0]->expression.vtype != TYPE_FLOAT) {
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
- parseerror(parser, "invalid type for prefix increment: %s", ty1);
+ compile_error(ast_ctx(exprs[0]), "invalid type for prefix increment: %s", ty1);
return false;
}
if (op->id == opid3('+','+','P'))
else
addop = INSTR_SUB_F;
if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
- parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
+ compile_error(ast_ctx(exprs[0]), "assignment to constant `%s`", asvalue[0]->name);
}
if (ast_istype(exprs[0], ast_entfield)) {
out = (ast_expression*)ast_binstore_new(ctx, INSTR_STOREP_F, addop,
/* prefix ++ */
if (exprs[0]->expression.vtype != TYPE_FLOAT) {
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
- parseerror(parser, "invalid type for suffix increment: %s", ty1);
+ compile_error(ast_ctx(exprs[0]), "invalid type for suffix increment: %s", ty1);
return false;
}
if (op->id == opid3('S','+','+')) {
subop = INSTR_ADD_F;
}
if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
- parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
+ compile_error(ast_ctx(exprs[0]), "assignment to constant `%s`", asvalue[0]->name);
}
if (ast_istype(exprs[0], ast_entfield)) {
out = (ast_expression*)ast_binstore_new(ctx, INSTR_STOREP_F, addop,
{
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
ast_type_to_string(exprs[1], ty2, sizeof(ty2));
- parseerror(parser, "invalid types used in expression: cannot add or subtract type %s and %s",
- ty1, ty2);
+ compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s",
+ ty1, ty2);
return false;
}
if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
- parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
+ compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name);
}
if (ast_istype(exprs[0], ast_entfield))
assignop = type_storep_instr[exprs[0]->expression.vtype];
exprs[0], exprs[1]);
break;
default:
- parseerror(parser, "invalid types used in expression: cannot add or subtract type %s and %s",
- type_name[exprs[0]->expression.vtype],
- type_name[exprs[1]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s",
+ type_name[exprs[0]->expression.vtype],
+ type_name[exprs[1]->expression.vtype]);
return false;
};
break;
{
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
ast_type_to_string(exprs[1], ty2, sizeof(ty2));
- parseerror(parser, "invalid types used in expression: %s and %s",
- ty1, ty2);
+ compile_error(ctx, "invalid types used in expression: %s and %s",
+ ty1, ty2);
return false;
}
if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
- parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
+ compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name);
}
if (ast_istype(exprs[0], ast_entfield))
assignop = type_storep_instr[exprs[0]->expression.vtype];
exprs[0], exprs[1]);
} else {
/* there's no DIV_VF */
- out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F,
- (ast_expression*)parser_const_float_1(parser),
- exprs[1]);
- if (!out)
+ if (CanConstFold1(exprs[1])) {
+ out = (ast_expression*)parser_const_float(parser, 1.0 / ConstF(1));
+ } else {
+ out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F,
+ (ast_expression*)parser_const_float_1(parser),
+ exprs[1]);
+ }
+ if (!out) {
+ compile_error(ctx, "internal error: failed to generate division");
return false;
+ }
out = (ast_expression*)ast_binstore_new(ctx, assignop, INSTR_MUL_VF,
exprs[0], out);
}
break;
default:
- parseerror(parser, "invalid types used in expression: cannot add or subtract type %s and %s",
- type_name[exprs[0]->expression.vtype],
- type_name[exprs[1]->expression.vtype]);
+ compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s",
+ type_name[exprs[0]->expression.vtype],
+ type_name[exprs[1]->expression.vtype]);
return false;
};
break;
if (NotSameType(TYPE_FLOAT)) {
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
ast_type_to_string(exprs[1], ty2, sizeof(ty2));
- parseerror(parser, "invalid types used in expression: %s and %s",
- ty1, ty2);
+ compile_error(ctx, "invalid types used in expression: %s and %s",
+ ty1, ty2);
return false;
}
if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
- parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
+ compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name);
}
if (ast_istype(exprs[0], ast_entfield))
assignop = type_storep_instr[exprs[0]->expression.vtype];
if (NotSameType(TYPE_FLOAT)) {
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
ast_type_to_string(exprs[1], ty2, sizeof(ty2));
- parseerror(parser, "invalid types used in expression: %s and %s",
- ty1, ty2);
+ compile_error(ctx, "invalid types used in expression: %s and %s",
+ ty1, ty2);
return false;
}
if (ast_istype(exprs[0], ast_entfield))
if (!out)
return false;
if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) {
- parseerror(parser, "assignment to constant `%s`", asvalue[0]->name);
+ compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name);
}
asbinstore = ast_binstore_new(ctx, assignop, INSTR_SUB_F, exprs[0], out);
asbinstore->keep_dest = true;
#undef NotSameType
if (!out) {
- parseerror(parser, "failed to apply operand %s", op->op);
+ compile_error(ctx, "failed to apply operand %s", op->op);
return false;
}
{
/* was a function call */
ast_expression *fun;
+ ast_value *funval = NULL;
ast_call *call;
size_t fid;
}
call = ast_call_new(sy->ops[vec_size(sy->ops)].ctx, fun);
- if (!call) {
- parseerror(parser, "internal error: failed to create ast_call node");
+ if (!call)
return false;
- }
if (fid+1 == vec_size(sy->out)) {
/* no arguments */
params->exprs = NULL;
ast_delete(params);
}
+ if (parser->max_param_count < paramcount)
+ parser->max_param_count = paramcount;
(void)!ast_call_check_types(call);
} else {
parseerror(parser, "invalid function call");
return false;
}
+ if (ast_istype(fun, ast_value)) {
+ funval = (ast_value*)fun;
+ if ((fun->expression.flags & AST_FLAG_VARIADIC) &&
+ !(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin))
+ {
+ call->va_count = (ast_expression*)parser_const_float(parser, (double)paramcount);
+ }
+ }
+
/* overwrite fid, the function, with a call */
sy->out[fid] = syexp(call->expression.node.context, (ast_expression*)call);
}
*/
while (vec_size(sy->ops)) {
- if (sy->ops[vec_size(sy->ops)-1].paren == SY_PAREN_FUNC) {
+ if (vec_last(sy->ops).paren == SY_PAREN_FUNC) {
if (!parser_close_call(parser, sy))
return false;
break;
}
- if (sy->ops[vec_size(sy->ops)-1].paren == SY_PAREN_EXPR) {
+ if (vec_last(sy->ops).paren == SY_PAREN_EXPR) {
+ if (!vec_size(sy->out)) {
+ compile_error(vec_last(sy->ops).ctx, "empty paren expression");
+ vec_shrinkby(sy->ops, 1);
+ return false;
+ }
vec_shrinkby(sy->ops, 1);
return !functions_only;
}
- if (sy->ops[vec_size(sy->ops)-1].paren == SY_PAREN_INDEX) {
+ if (vec_last(sy->ops).paren == SY_PAREN_INDEX) {
if (functions_only)
return false;
/* pop off the parenthesis */
return false;
return true;
}
- if (sy->ops[vec_size(sy->ops)-1].paren == SY_PAREN_TERNARY) {
+ if (vec_last(sy->ops).paren == SY_PAREN_TERNARY) {
if (functions_only)
return false;
if (vec_last(parser->pot) != POT_TERNARY1) {
}
}
+static ast_expression* parse_vararg_do(parser_t *parser)
+{
+ ast_expression *idx, *out;
+ ast_value *typevar;
+ ast_value *funtype = parser->function->vtype;
+
+ lex_ctx ctx = parser_ctx(parser);
+
+ if (!parser_next(parser) || parser->tok != '(') {
+ parseerror(parser, "expected parameter index and type in parenthesis");
+ return NULL;
+ }
+ if (!parser_next(parser)) {
+ parseerror(parser, "error parsing parameter index");
+ return NULL;
+ }
+
+ idx = parse_expression_leave(parser, true, false, false);
+ if (!idx)
+ return NULL;
+
+ if (parser->tok != ',') {
+ ast_unref(idx);
+ parseerror(parser, "expected comma after parameter index");
+ return NULL;
+ }
+
+ if (!parser_next(parser) || (parser->tok != TOKEN_IDENT && parser->tok != TOKEN_TYPENAME)) {
+ ast_unref(idx);
+ parseerror(parser, "expected typename for vararg");
+ return NULL;
+ }
+
+ typevar = parse_typename(parser, NULL, NULL);
+ if (!typevar) {
+ ast_unref(idx);
+ return NULL;
+ }
+
+ if (parser->tok != ')') {
+ ast_unref(idx);
+ ast_delete(typevar);
+ parseerror(parser, "expected closing paren");
+ return NULL;
+ }
+
+#if 0
+ if (!parser_next(parser)) {
+ ast_unref(idx);
+ ast_delete(typevar);
+ parseerror(parser, "parse error after vararg");
+ return NULL;
+ }
+#endif
+
+ if (!parser->function->varargs) {
+ ast_unref(idx);
+ ast_delete(typevar);
+ parseerror(parser, "function has no variable argument list");
+ return NULL;
+ }
+
+ if (funtype->expression.varparam &&
+ !ast_compare_type((ast_expression*)typevar, (ast_expression*)funtype->expression.varparam))
+ {
+ char ty1[1024];
+ char ty2[1024];
+ ast_type_to_string((ast_expression*)typevar, ty1, sizeof(ty1));
+ ast_type_to_string((ast_expression*)funtype->expression.varparam, ty2, sizeof(ty2));
+ compile_error(ast_ctx(typevar),
+ "function was declared to take varargs of type `%s`, requested type is: %s",
+ ty2, ty1);
+ }
+
+ out = (ast_expression*)ast_array_index_new(ctx, (ast_expression*)(parser->function->varargs), idx);
+ ast_type_adopt(out, typevar);
+ ast_delete(typevar);
+ return out;
+}
+
+static ast_expression* parse_vararg(parser_t *parser)
+{
+ bool old_noops = parser->lex->flags.noops;
+ enum parser_pot *old_pot = parser->pot;
+
+ ast_expression *out;
+
+ parser->pot = NULL;
+ parser->lex->flags.noops = true;
+ out = parse_vararg_do(parser);
+
+ parser->pot = old_pot;
+ parser->lex->flags.noops = old_noops;
+ return out;
+}
+
static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels)
{
ast_expression *expr = NULL;
shunt sy;
+ size_t i;
bool wantop = false;
/* only warn once about an assignment in a truth value because the current code
* would trigger twice on: if(a = b && ...), once for the if-truth-value, once for the && part
goto onerr;
}
}
+ else if (parser->tok == TOKEN_DOTS)
+ {
+ ast_expression *va;
+ if (!OPTS_FLAG(VARIADIC_ARGS)) {
+ parseerror(parser, "cannot access varargs (try -fvariadic-args)");
+ goto onerr;
+ }
+ if (wantop) {
+ parseerror(parser, "expected operator or end of statement");
+ goto onerr;
+ }
+ wantop = true;
+ va = parse_vararg(parser);
+ if (!va)
+ goto onerr;
+ vec_push(sy.out, syexp(parser_ctx(parser), va));
+ DEBUGSHUNTDO(con_out("push `...`\n"));
+ }
else if (parser->tok == TOKEN_IDENT)
{
const char *ctoken = parser_tokval(parser);
}
else
{
- size_t i;
- char *correct = NULL;
+ char *correct = NULL;
/*
* sometimes people use preprocessing predefs without enabling them
* We should also consider adding correction tables for
* other things as well.
*/
- if (OPTS_FLAG(ENHANCED_DIAGNOSTICS)) {
+ if (opts.correction) {
correction_t corr;
correct_init(&corr);
onerr:
parser->lex->flags.noops = true;
+ for (i = 0; i < vec_size(sy.out); ++i) {
+ if (sy.out[i].out)
+ ast_unref(sy.out[i].out);
+ }
vec_free(sy.out);
vec_free(sy.ops);
return NULL;
return false;
}
- if (var->expression.flags & AST_FLAG_VARIADIC) {
+ if (!OPTS_FLAG(VARIADIC_ARGS) && var->expression.flags & AST_FLAG_VARIADIC) {
if (parsewarning(parser, WARN_VARIADIC_FUNCTION,
- "variadic function with implementation will not be able to access additional parameters"))
+ "variadic function with implementation will not be able to access additional parameters (try -fvariadic-args)"))
{
return false;
}
}
}
+ func = ast_function_new(ast_ctx(var), var->name, var);
+ if (!func) {
+ parseerror(parser, "failed to allocate function for `%s`", var->name);
+ ast_block_delete(block);
+ goto enderr;
+ }
+ vec_push(parser->functions, func);
+
parser_enterblock(parser);
for (parami = 0; parami < vec_size(var->expression.params); ++parami) {
if (!create_vector_members(param, me)) {
ast_block_delete(block);
- return false;
+ goto enderrfn;
}
for (e = 0; e < 3; ++e) {
}
}
- func = ast_function_new(ast_ctx(var), var->name, var);
- if (!func) {
- parseerror(parser, "failed to allocate function for `%s`", var->name);
- ast_block_delete(block);
- goto enderr;
+ if (var->argcounter) {
+ ast_value *argc = ast_value_new(ast_ctx(var), var->argcounter, TYPE_FLOAT);
+ parser_addlocal(parser, argc->name, (ast_expression*)argc);
+ func->argc = argc;
+ }
+
+ if (OPTS_FLAG(VARIADIC_ARGS) && var->expression.flags & AST_FLAG_VARIADIC) {
+ char name[1024];
+ ast_value *varargs = ast_value_new(ast_ctx(var), "reserved:va_args", TYPE_ARRAY);
+ varargs->expression.flags |= AST_FLAG_IS_VARARG;
+ varargs->expression.next = (ast_expression*)ast_value_new(ast_ctx(var), NULL, TYPE_VECTOR);
+ varargs->expression.count = 0;
+ snprintf(name, sizeof(name), "%s##va##SET", var->name);
+ if (!parser_create_array_setter_proto(parser, varargs, name)) {
+ ast_delete(varargs);
+ ast_block_delete(block);
+ goto enderrfn;
+ }
+ snprintf(name, sizeof(name), "%s##va##GET", var->name);
+ if (!parser_create_array_getter_proto(parser, varargs, varargs->expression.next, name)) {
+ ast_delete(varargs);
+ ast_block_delete(block);
+ goto enderrfn;
+ }
+ func->varargs = varargs;
+
+ func->fixedparams = parser_const_float(parser, vec_size(var->expression.params));
}
- vec_push(parser->functions, func);
parser->function = func;
if (!parse_block_into(parser, block)) {
return retval;
enderrfn:
+ (void)!parser_leaveblock(parser);
vec_pop(parser->functions);
ast_function_delete(func);
var->constval.vfunc = NULL;
enderr:
- (void)!parser_leaveblock(parser);
parser->function = old;
return false;
}
if (!subscript)
return NULL;
+ subscript->expression.next = ast_type_copy(ast_ctx(subscript), (ast_expression*)subscript);
+ subscript->expression.vtype = TYPE_FIELD;
+
entfield = ast_entfield_new_force(ctx,
(ast_expression*)entity,
(ast_expression*)subscript,
return true;
}
-static bool parser_create_array_setter(parser_t *parser, ast_value *array, const char *funcname)
+static ast_value* parser_create_array_setter_proto(parser_t *parser, ast_value *array, const char *funcname)
{
- ast_expression *root = NULL;
ast_value *index = NULL;
ast_value *value = NULL;
ast_function *func;
if (!ast_istype(array->expression.next, ast_value)) {
parseerror(parser, "internal error: array accessor needs to build an ast_value with a copy of the element type");
- return false;
+ return NULL;
}
if (!parser_create_array_accessor(parser, array, funcname, &fval))
- return false;
+ return NULL;
func = fval->constval.vfunc;
fval->expression.next = (ast_expression*)ast_value_new(ast_ctx(array), "<void>", TYPE_VOID);
vec_push(fval->expression.params, index);
vec_push(fval->expression.params, value);
- root = array_setter_node(parser, array, index, value, 0, array->expression.count);
- if (!root) {
- parseerror(parser, "failed to build accessor search tree");
- goto cleanup;
- }
-
array->setter = fval;
- return ast_block_add_expr(func->blocks[0], root);
+ return fval;
cleanup:
if (index) ast_delete(index);
if (value) ast_delete(value);
- if (root) ast_delete(root);
ast_delete(func);
ast_delete(fval);
- return false;
+ return NULL;
+}
+
+static bool parser_create_array_setter_impl(parser_t *parser, ast_value *array)
+{
+ ast_expression *root = NULL;
+ root = array_setter_node(parser, array,
+ array->setter->expression.params[0],
+ array->setter->expression.params[1],
+ 0, array->expression.count);
+ if (!root) {
+ parseerror(parser, "failed to build accessor search tree");
+ return false;
+ }
+ if (!ast_block_add_expr(array->setter->constval.vfunc->blocks[0], root)) {
+ ast_delete(root);
+ return false;
+ }
+ return true;
+}
+
+static bool parser_create_array_setter(parser_t *parser, ast_value *array, const char *funcname)
+{
+ if (!parser_create_array_setter_proto(parser, array, funcname))
+ return false;
+ return parser_create_array_setter_impl(parser, array);
}
static bool parser_create_array_field_setter(parser_t *parser, ast_value *array, const char *funcname)
return false;
}
-static bool parser_create_array_getter(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname)
+static ast_value* parser_create_array_getter_proto(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname)
{
- ast_expression *root = NULL;
ast_value *index = NULL;
ast_value *fval;
ast_function *func;
*/
if (!ast_istype(array->expression.next, ast_value)) {
parseerror(parser, "internal error: array accessor needs to build an ast_value with a copy of the element type");
- return false;
+ return NULL;
}
if (!parser_create_array_accessor(parser, array, funcname, &fval))
- return false;
+ return NULL;
func = fval->constval.vfunc;
fval->expression.next = ast_type_copy(ast_ctx(array), elemtype);
}
vec_push(fval->expression.params, index);
- root = array_getter_node(parser, array, index, 0, array->expression.count);
- if (!root) {
- parseerror(parser, "failed to build accessor search tree");
- goto cleanup;
- }
-
array->getter = fval;
- return ast_block_add_expr(func->blocks[0], root);
+ return fval;
cleanup:
if (index) ast_delete(index);
- if (root) ast_delete(root);
ast_delete(func);
ast_delete(fval);
- return false;
+ return NULL;
+}
+
+static bool parser_create_array_getter_impl(parser_t *parser, ast_value *array)
+{
+ ast_expression *root = NULL;
+
+ root = array_getter_node(parser, array, array->getter->expression.params[0], 0, array->expression.count);
+ if (!root) {
+ parseerror(parser, "failed to build accessor search tree");
+ return false;
+ }
+ if (!ast_block_add_expr(array->getter->constval.vfunc->blocks[0], root)) {
+ ast_delete(root);
+ return false;
+ }
+ return true;
+}
+
+static bool parser_create_array_getter(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname)
+{
+ if (!parser_create_array_getter_proto(parser, array, elemtype, funcname))
+ return false;
+ return parser_create_array_getter_impl(parser, array);
}
static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef);
ast_value *fval;
bool first = true;
bool variadic = false;
+ ast_value *varparam = NULL;
+ char *argcounter = NULL;
ctx = parser_ctx(parser);
if (parser->tok == TOKEN_DOTS) {
/* '...' indicates a varargs function */
variadic = true;
- if (!parser_next(parser)) {
- parseerror(parser, "expected parameter");
- return NULL;
- }
- if (parser->tok != ')') {
+ if (!parser_next(parser) || (parser->tok != ')' && parser->tok != TOKEN_IDENT)) {
parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
goto on_error;
}
+ if (parser->tok == TOKEN_IDENT) {
+ argcounter = util_strdup(parser_tokval(parser));
+ if (!parser_next(parser) || parser->tok != ')') {
+ parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
+ goto on_error;
+ }
+ }
}
else
{
parseerror(parser, "type not supported as part of a parameter list: %s", tname);
goto on_error;
}
+ /* type-restricted varargs */
+ if (parser->tok == TOKEN_DOTS) {
+ variadic = true;
+ varparam = vec_last(params);
+ vec_pop(params);
+ if (!parser_next(parser) || (parser->tok != ')' && parser->tok != TOKEN_IDENT)) {
+ parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
+ goto on_error;
+ }
+ if (parser->tok == TOKEN_IDENT) {
+ argcounter = util_strdup(parser_tokval(parser));
+ if (!parser_next(parser) || parser->tok != ')') {
+ parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
+ goto on_error;
+ }
+ }
+ }
}
}
fval->expression.flags |= AST_FLAG_VARIADIC;
var = fval;
- var->expression.params = params;
+ var->expression.params = params;
+ var->expression.varparam = (ast_expression*)varparam;
+ var->argcounter = argcounter;
params = NULL;
return var;
on_error:
+ if (argcounter)
+ mem_d(argcounter);
ast_delete(var);
for (i = 0; i < vec_size(params); ++i)
ast_delete(params[i]);
if (!var) {
if (name)
mem_d((void*)name);
- ast_delete(var);
return NULL;
}
}
goto cleanup;
*/
}
- if (opts.standard == COMPILER_QCC &&
+ if ((opts.standard == COMPILER_QCC || opts.standard == COMPILER_FTEQCC) &&
(old = parser_find_global(parser, var->name)))
{
parseerror(parser, "cannot declare a field and a global of the same name with -std=qcc");
if (OPTS_FLAG(UNTYPED_NIL))
util_htset(parser->htglobals, "nil", (void*)parser->nil);
+ parser->max_param_count = 1;
+
parser->const_vec[0] = ast_value_new(empty_ctx, "<vector.x>", TYPE_NOEXPR);
parser->const_vec[1] = ast_value_new(empty_ctx, "<vector.y>", TYPE_NOEXPR);
parser->const_vec[2] = ast_value_new(empty_ctx, "<vector.z>", TYPE_NOEXPR);
return false;
}
}
- if (parser->reserved_version &&
- !ast_global_codegen(parser->reserved_version, ir, false))
- {
- con_out("failed to generate reserved::version");
- ir_builder_delete(ir);
- return false;
+ /* Build function vararg accessor ast tree now before generating
+ * immediates, because the accessors may add new immediates
+ */
+ for (i = 0; i < vec_size(parser->functions); ++i) {
+ ast_function *f = parser->functions[i];
+ if (f->varargs) {
+ if (parser->max_param_count > vec_size(f->vtype->expression.params)) {
+ f->varargs->expression.count = parser->max_param_count - vec_size(f->vtype->expression.params);
+ if (!parser_create_array_setter_impl(parser, f->varargs)) {
+ con_out("failed to generate vararg setter for %s\n", f->name);
+ ir_builder_delete(ir);
+ return false;
+ }
+ if (!parser_create_array_getter_impl(parser, f->varargs)) {
+ con_out("failed to generate vararg getter for %s\n", f->name);
+ ir_builder_delete(ir);
+ return false;
+ }
+ } else {
+ ast_delete(f->varargs);
+ f->varargs = NULL;
+ }
+ }
}
+ /* Now we can generate immediates */
for (i = 0; i < vec_size(parser->imm_float); ++i) {
if (!ast_global_codegen(parser->imm_float[i], ir, false)) {
con_out("failed to generate global %s\n", parser->imm_float[i]->name);
return false;
}
}
+ if (parser->reserved_version &&
+ !ast_global_codegen(parser->reserved_version, ir, false))
+ {
+ con_out("failed to generate reserved::version");
+ ir_builder_delete(ir);
+ return false;
+ }
for (i = 0; i < vec_size(parser->functions); ++i) {
- if (!ast_function_codegen(parser->functions[i], ir)) {
- con_out("failed to generate function %s\n", parser->functions[i]->name);
+ ast_function *f = parser->functions[i];
+ if (!ast_function_codegen(f, ir)) {
+ con_out("failed to generate function %s\n", f->name);
ir_builder_delete(ir);
return false;
}