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;
ht htglobals;
ht *typedefs;
+ /* same as above but for the spelling corrector */
+ correct_trie_t **correct_variables;
+ size_t ***correct_variables_score; /* vector of vector of size_t* */
+
/* not to be used directly, we use the hash table */
ast_expression **_locals;
size_t *_blocklocals;
/* we store the '=' operator info */
const oper_info *assign_op;
- /* TYPE_FIELD -> parser_find_fields is used instead of find_var
- * TODO: TYPE_VECTOR -> x, y and z are accepted in the gmqcc standard
- * anything else: type error
- */
- qcint memberof;
-
/* Keep track of our ternary vs parenthesis nesting state.
* If we reach a 'comma' operator in a ternary without a paren,
* we shall trigger -Wternary-precedence.
*/
enum parser_pot *pot;
+ /* magic values */
+ ast_value *const_vec[3];
+
/* pragma flags */
bool noref;
+
+ /* collected information */
+ size_t max_param_count;
} parser_t;
static const ast_expression *intrinsic_debug_typestring = (ast_expression*)0x10;
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 void parser_addglobal(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 qualifier, ast_value *cached_typedef, bool noref, bool is_static, uint32_t qflags, char *vstring);
static ast_block* parse_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, 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 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;
asvalue[i] = (ast_value*)exprs[i];
if (exprs[i]->expression.vtype == TYPE_NOEXPR &&
- !(i != 0 && op->id == opid2('?',':')))
+ !(i != 0 && op->id == opid2('?',':')) &&
+ !(i == 1 && op->id == opid1('.')))
{
if (ast_istype(exprs[i], ast_label))
compile_error(ast_ctx(exprs[i]), "expected expression, got an unknown identifier");
return false;
case opid1('.'):
- if (exprs[0]->expression.vtype == TYPE_ENTITY) {
+ if (exprs[0]->expression.vtype == TYPE_VECTOR &&
+ exprs[1]->expression.vtype == TYPE_NOEXPR)
+ {
+ if (exprs[1] == (ast_expression*)parser->const_vec[0])
+ out = (ast_expression*)ast_member_new(ctx, exprs[0], 0, NULL);
+ else if (exprs[1] == (ast_expression*)parser->const_vec[1])
+ out = (ast_expression*)ast_member_new(ctx, exprs[0], 1, NULL);
+ 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");
+ 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");
return false;
out = (ast_expression*)ast_entfield_new(ctx, exprs[0], exprs[1]);
}
else if (exprs[0]->expression.vtype == TYPE_VECTOR) {
- parseerror(parser, "internal error: vector access is not supposed to be handled at this point");
+ parseerror(parser, "vectors cannot be accessed this way");
return false;
}
else {
exprs[0], exprs[1]);
break;
case opid1('^'):
- parseerror(parser, "TODO: bitxor");
+ compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-xor via ^");
return false;
case opid2('<','<'):
case opid2('>','>'):
+ if (CanConstFold(exprs[0], exprs[1]) && ! NotSameType(TYPE_FLOAT)) {
+ if (op->id == opid2('<','<'))
+ out = (ast_expression*)parser_const_float(parser, (double)((int)(ConstF(0)) << (int)(ConstF(1))));
+ else
+ out = (ast_expression*)parser_const_float(parser, (double)((int)(ConstF(0)) >> (int)(ConstF(1))));
+ break;
+ }
case opid3('<','<','='):
case opid3('>','>','='):
- parseerror(parser, "TODO: shifts");
+ compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-shifts");
return false;
case opid2('|','|'):
{
/* 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);
ast_expression *expr = NULL;
shunt sy;
bool wantop = false;
- bool gotmemberof = 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
*/
while (true)
{
- if (gotmemberof)
- gotmemberof = false;
- else
- parser->memberof = 0;
-
if (OPTS_FLAG(TRANSLATABLE_STRINGS) &&
parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "_"))
{
}
else if (parser->tok == TOKEN_IDENT)
{
+ const char *ctoken = parser_tokval(parser);
+ ast_expression *prev = vec_size(sy.out) ? vec_last(sy.out).out : NULL;
ast_expression *var;
if (wantop) {
parseerror(parser, "expected operator or end of statement");
goto onerr;
}
wantop = true;
- /* variable */
- if (opts.standard == COMPILER_GMQCC)
+ /* a_vector.{x,y,z} */
+ if (!vec_size(sy.ops) ||
+ !vec_last(sy.ops).etype ||
+ operators[vec_last(sy.ops).etype-1].id != opid1('.') ||
+ (prev >= intrinsic_debug_typestring &&
+ prev <= intrinsic_debug_typestring))
{
- if (parser->memberof == TYPE_ENTITY) {
- /* still get vars first since there could be a fieldpointer */
- var = parser_find_var(parser, parser_tokval(parser));
- if (!var)
- var = parser_find_field(parser, parser_tokval(parser));
- }
- else if (parser->memberof == TYPE_VECTOR)
- {
- parseerror(parser, "TODO: implement effective vector member access");
- goto onerr;
- }
- else if (parser->memberof) {
- parseerror(parser, "namespace for member not found");
- goto onerr;
- }
- else
- var = parser_find_var(parser, parser_tokval(parser));
+ /* When adding more intrinsics, fix the above condition */
+ prev = NULL;
+ }
+ if (prev && prev->expression.vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1])
+ {
+ var = (ast_expression*)parser->const_vec[ctoken[0]-'x'];
} else {
var = parser_find_var(parser, parser_tokval(parser));
if (!var)
}
else
{
+ size_t i;
+ char *correct = NULL;
+
/*
* sometimes people use preprocessing predefs without enabling them
* i've done this thousands of times already myself. Lets check for
* it in the predef table. And diagnose it better :)
*/
if (!OPTS_FLAG(FTEPP_PREDEFS)) {
- size_t i;
for (i = 0; i < sizeof(ftepp_predefs)/sizeof(*ftepp_predefs); i++) {
if (!strcmp(ftepp_predefs[i].name, parser_tokval(parser))) {
parseerror(parser, "unexpected ident: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser));
}
}
+ /*
+ * 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_FLAG(ENHANCED_DIAGNOSTICS)) {
+ 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 if (correct) {
+ mem_d(correct);
+ correct = NULL;
+ }
+ }
+ correct_free(&corr);
+
+ if (correct) {
+ parseerror(parser, "unexpected ident: %s (did you mean %s?)", parser_tokval(parser), correct);
+ mem_d(correct);
+ goto onerr;
+ }
+ }
parseerror(parser, "unexpected ident: %s", parser_tokval(parser));
goto onerr;
}
olast = NULL;
}
- if (op->id == opid1('.') && opts.standard == COMPILER_GMQCC) {
- /* for gmqcc standard: open up the namespace of the previous type */
- ast_expression *prevex = vec_last(sy.out).out;
- if (!prevex) {
- parseerror(parser, "unexpected member operator");
- goto onerr;
- }
- if (prevex->expression.vtype == TYPE_ENTITY)
- parser->memberof = TYPE_ENTITY;
- else if (prevex->expression.vtype == TYPE_VECTOR)
- parser->memberof = TYPE_VECTOR;
- else {
- parseerror(parser, "type error: type has no members");
- goto onerr;
- }
- gotmemberof = true;
- }
-
if (op->id == opid1('(')) {
if (wantop) {
size_t sycount = vec_size(sy.out);
goto onerr;
}
if (parser->tok == ';' ||
- (!parens && parser->tok == ']'))
+ (!parens && (parser->tok == ']' || parser->tok == ')' || parser->tok == '}')))
{
break;
}
ast_expression *e = parse_expression_leave(parser, stopatcomma, false, with_labels);
if (!e)
return NULL;
+ if (parser->tok != ';') {
+ parseerror(parser, "semicolon expected after expression");
+ ast_unref(e);
+ return NULL;
+ }
if (!parser_next(parser)) {
- ast_delete(e);
+ ast_unref(e);
return NULL;
}
return e;
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_pop(parser->typedefs);
vec_pop(parser->_block_ctx);
+
return rv;
}
{
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)
ast_delete(cond);
return false;
}
+ if (!ontrue)
+ ontrue = (ast_expression*)ast_block_new(parser_ctx(parser));
/* check for an else */
if (!strcmp(parser_tokval(parser), "else")) {
/* parse into the 'else' branch */
return false;
}
+ if (!vec_size(loops)) {
+ if (is_continue)
+ parseerror(parser, "`continue` can only be used inside loops");
+ else
+ parseerror(parser, "`break` can only be used inside loops or switches");
+ }
+
if (parser->tok == TOKEN_IDENT) {
if (!OPTS_FLAG(LOOP_LABELS))
parseerror(parser, "labeled loops not activated, try using -floop-labels");
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;
}
}
+static bool parse_enum(parser_t *parser)
+{
+ qcfloat num = 0;
+ ast_value **values = NULL;
+ ast_value *var = NULL;
+ ast_value *asvalue;
+
+ ast_expression *old;
+
+ if (!parser_next(parser) || parser->tok != '{') {
+ parseerror(parser, "expected `{` after `enum` keyword");
+ return false;
+ }
+
+ while (true) {
+ if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
+ if (parser->tok == '}') {
+ /* allow an empty enum */
+ break;
+ }
+ parseerror(parser, "expected identifier or `}`");
+ goto onerror;
+ }
+
+ old = parser_find_field(parser, parser_tokval(parser));
+ if (!old)
+ old = parser_find_global(parser, parser_tokval(parser));
+ if (old) {
+ parseerror(parser, "value `%s` has already been declared here: %s:%i",
+ parser_tokval(parser), ast_ctx(old).file, ast_ctx(old).line);
+ goto onerror;
+ }
+
+ var = ast_value_new(parser_ctx(parser), parser_tokval(parser), TYPE_FLOAT);
+ vec_push(values, var);
+ var->cvq = CV_CONST;
+ var->hasvalue = true;
+ var->constval.vfloat = num++;
+
+ parser_addglobal(parser, var->name, (ast_expression*)var);
+
+ if (!parser_next(parser)) {
+ parseerror(parser, "expected `=`, `}` or comma after identifier");
+ goto onerror;
+ }
+
+ if (parser->tok == ',')
+ continue;
+ if (parser->tok == '}')
+ break;
+ if (parser->tok != '=') {
+ parseerror(parser, "expected `=`, `}` or comma after identifier");
+ goto onerror;
+ }
+
+ if (!parser_next(parser)) {
+ parseerror(parser, "expected expression after `=`");
+ goto onerror;
+ }
+
+ /* We got a value! */
+ old = parse_expression_leave(parser, true, false, false);
+ asvalue = (ast_value*)old;
+ if (!ast_istype(old, ast_value) || asvalue->cvq != CV_CONST || !asvalue->hasvalue) {
+ compile_error(ast_ctx(var), "constant value or expression expected");
+ goto onerror;
+ }
+ num = (var->constval.vfloat = asvalue->constval.vfloat) + 1;
+
+ if (parser->tok == '}')
+ break;
+ if (parser->tok != ',') {
+ parseerror(parser, "expected `}` or comma after expression");
+ goto onerror;
+ }
+ }
+
+ if (parser->tok != '}') {
+ parseerror(parser, "internal error: breaking without `}`");
+ goto onerror;
+ }
+
+ if (!parser_next(parser) || parser->tok != ';') {
+ parseerror(parser, "expected semicolon after enumeration");
+ goto onerror;
+ }
+
+ if (!parser_next(parser)) {
+ parseerror(parser, "parse error after enumeration");
+ goto onerror;
+ }
+
+ vec_free(values);
+ return true;
+
+onerror:
+ vec_free(values);
+ return false;
+}
+
static bool parse_block_into(parser_t *parser, ast_block *block)
{
bool retval = true;
return false;
}
- vec_push(parser->globals, (ast_expression*)thinkfunc);
- util_htset(parser->htglobals, thinkfunc->name, thinkfunc);
+ parser_addglobal(parser, thinkfunc->name, (ast_expression*)thinkfunc);
+
nextthink = (ast_expression*)thinkfunc;
} else {
}
vec_push(parser->functions, func);
+ 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]);
}
}
else {
- vec_push(parser->globals, (ast_expression*)var);
- util_htset(parser->htglobals, var->name, var);
+ parser_addglobal(parser, var->name, (ast_expression*)var);
if (isvector) {
for (i = 0; i < 3; ++i) {
- vec_push(parser->globals, (ast_expression*)me[i]);
- util_htset(parser->htglobals, me[i]->name, me[i]);
+ parser_addglobal(parser, me[i]->name, (ast_expression*)me[i]);
}
}
}
/* 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);
return false;
return parse_variable(parser, NULL, true, cvq, NULL, noref, is_static, qflags, vstring);
}
+ else if (parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "enum"))
+ {
+ return parse_enum(parser);
+ }
else if (parser->tok == TOKEN_KEYWORD)
{
if (!strcmp(parser_tokval(parser), "typedef")) {
vec_push(parser->typedefs, util_htnew(TYPEDEF_HT_SIZE));
vec_push(parser->_blocktypedefs, 0);
+ /* corrector */
+ vec_push(parser->correct_variables, correct_trie_new());
+ vec_push(parser->correct_variables_score, NULL);
+
empty_ctx.file = "<internal>";
empty_ctx.line = 0;
parser->nil = ast_value_new(empty_ctx, "nil", TYPE_NIL);
parser->nil->cvq = CV_CONST;
if (OPTS_FLAG(UNTYPED_NIL))
util_htset(parser->htglobals, "nil", (void*)parser->nil);
+
+ 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;
}
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);
ast_value_delete(parser->nil);
+ ast_value_delete(parser->const_vec[0]);
+ ast_value_delete(parser->const_vec[1]);
+ ast_value_delete(parser->const_vec[2]);
+
mem_d(parser);
}
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;
}