ast_value *imm_float_one;
ast_value *imm_vector_zero;
ast_value *nil;
+ ast_value *reserved_version;
size_t crc_globals;
size_t crc_fields;
/* 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;
{
/* was a function call */
ast_expression *fun;
+ ast_value *funval = NULL;
ast_call *call;
size_t fid;
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))
+ {
+ size_t va_count;
+ if (paramcount < vec_size(fun->expression.params))
+ va_count = 0;
+ else
+ va_count = paramcount - vec_size(fun->expression.params);
+ call->va_count = (ast_expression*)parser_const_float(parser, (double)va_count);
+ }
+ }
+
/* overwrite fid, the function, with a call */
sy->out[fid] = syexp(call->expression.node.context, (ast_expression*)call);
}
}
+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;
goto onerr;
}
}
+ else if (parser->tok == TOKEN_DOTS)
+ {
+ ast_expression *va;
+ 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 if (!strcmp(parser_tokval(parser), "deprecated") && !(flags & AST_FLAG_DEPRECATED)) {
flags |= AST_FLAG_DEPRECATED;
*message = NULL;
-
+
if (!parser_next(parser)) {
parseerror(parser, "parse error in attribute");
goto argerr;
}
}
}
- else if (!strcmp(parser_tokval(parser), "static"))
+ else if (with_local && !strcmp(parser_tokval(parser), "static"))
had_static = true;
else if (!strcmp(parser_tokval(parser), "const"))
had_const = true;
old = parse_expression_leave(parser, true, false, false);
asvalue = (ast_value*)old;
if (!ast_istype(old, ast_value) || asvalue->cvq != CV_CONST || !asvalue->hasvalue) {
- parseerror(parser, "enumeration value for must be a constant");
+ compile_error(ast_ctx(var), "constant value or expression expected");
goto onerror;
}
num = (var->constval.vfloat = asvalue->constval.vfloat) + 1;
}
vec_push(parser->functions, func);
+ 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 (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 enderr;
+ }
+ 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 enderr;
+ }
+ func->varargs = varargs;
+ }
+
parser->function = func;
if (!parse_block_into(parser, block)) {
ast_block_delete(block);
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]);
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);
+
+ if (opts.add_info) {
+ parser->reserved_version = ast_value_new(empty_ctx, "reserved:version", TYPE_STRING);
+ parser->reserved_version->cvq = CV_CONST;
+ parser->reserved_version->hasvalue = true;
+ parser->reserved_version->expression.flags |= AST_FLAG_INCLUDE_DEF;
+ parser->reserved_version->constval.vstring = util_strdup(GMQCC_FULL_VERSION_STRING);
+ } else {
+ parser->reserved_version = NULL;
+ }
return true;
}
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;
}