*/
#include <stdio.h>
#include <stdarg.h>
+#include <math.h>
#include "gmqcc.h"
#include "lexer.h"
static ast_expression* parser_find_global(parser_t *parser, const char *name)
{
+ ast_expression *var = (ast_expression*)util_htget(parser->aliases, parser_tokval(parser));
+ if (var)
+ return var;
return (ast_expression*)util_htget(parser->htglobals, name);
}
return NULL;
}
+/* include intrinsics */
+#include "intrin.h"
+
typedef struct
{
size_t etype; /* 0 = expression, others are operators */
return false;
}
break;
+
case opid1('%'):
+ if (NotSameType(TYPE_FLOAT)) {
+ compile_error(ctx, "invalid types used in expression: cannot perform modulo operation 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])) {
+ out = (ast_expression*)parser_const_float(parser,
+ (float)(((qcint)ConstF(0)) % ((qcint)ConstF(1))));
+ } else {
+ /* generate a call to __builtin_mod */
+ ast_expression *mod = intrin_func(parser, "mod");
+ ast_call *call = NULL;
+ if (!mod) return false; /* can return null for missing floor */
+
+ call = ast_call_new(parser_ctx(parser), mod);
+ vec_push(call->params, exprs[0]);
+ vec_push(call->params, exprs[1]);
+
+ out = (ast_expression*)call;
+ }
+ break;
+
case opid2('%','='):
- compile_error(ctx, "qc does not have a modulo operator");
+ compile_error(ctx, "%= is unimplemented");
return false;
+
case opid1('|'):
case opid1('&'):
if (NotSameType(TYPE_FLOAT)) {
out = (ast_expression*)ast_ternary_new(ctx, exprs[0], exprs[1], exprs[2]);
break;
+ case opid2('*', '*'):
+ if (NotSameType(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 exponentiation: %s and %s",
+ ty1, ty2);
+
+ return false;
+ }
+
+ if (CanConstFold(exprs[0], exprs[1])) {
+ out = (ast_expression*)parser_const_float(parser, powf(ConstF(0), ConstF(1)));
+ } else {
+ ast_call *gencall = ast_call_new(parser_ctx(parser), intrin_func(parser, "pow"));
+ vec_push(gencall->params, exprs[0]);
+ vec_push(gencall->params, exprs[1]);
+ out = (ast_expression*)gencall;
+ }
+ break;
+
case opid3('<','=','>'): /* -1, 0, or 1 */
if (NotSameType(TYPE_FLOAT)) {
ast_type_to_string(exprs[0], ty1, sizeof(ty1));
} else {
ast_binary *eq = ast_binary_new(ctx, INSTR_EQ_F, exprs[0], exprs[1]);
- eq->refs = false; /* references nothing */
+ eq->refs = (ast_binary_ref)false; /* references nothing */
/* if (lt) { */
out = (ast_expression*)ast_ternary_new(ctx,
if(CanConstFold1(exprs[0]))
out = (ast_expression*)parser_const_float(parser, ~(qcint)ConstF(0));
else
- out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser_const_float_neg1(parser), exprs[0]);
+ out = (ast_expression*)
+ ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser_const_float_neg1(parser), exprs[0]);
break;
}
#undef NotSameType
/* intrinsics */
if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) {
var = (ast_expression*)intrinsic_debug_typestring;
+ }
+ /* now we try for the real intrinsic hashtable. If the string
+ * begins with __builtin, we simply skip past it, otherwise we
+ * use the identifier as is.
+ */
+ else if (!strncmp(parser_tokval(parser), "__builtin_", 10)) {
+ var = intrin_func(parser, parser_tokval(parser) + 10 /* skip __builtin */);
} else {
- const char *alias = util_htget(parser->aliases, parser_tokval(parser));
- if (alias)
- var = (ast_expression*)parser_find_var(parser, alias);
+ var = intrin_func(parser, parser_tokval(parser));
}
if (!var) {
static bool parse_enum(parser_t *parser)
{
+ bool flag = false;
+ bool reverse = false;
qcfloat num = 0;
ast_value **values = NULL;
ast_value *var = NULL;
ast_expression *old;
- if (!parser_next(parser) || parser->tok != '{') {
- parseerror(parser, "expected `{` after `enum` keyword");
+ if (!parser_next(parser) || (parser->tok != '{' && parser->tok != ':')) {
+ parseerror(parser, "expected `{` or `:` after `enum` keyword");
return false;
}
+ /* enumeration attributes (can add more later) */
+ if (parser->tok == ':') {
+ if (!parser_next(parser) || parser->tok != TOKEN_IDENT){
+ parseerror(parser, "expected `flag` or `reverse` for enumeration attribute");
+ return false;
+ }
+
+ /* attributes? */
+ if (!strcmp(parser_tokval(parser), "flag")) {
+ num = 1;
+ flag = true;
+ }
+ else if (!strcmp(parser_tokval(parser), "reverse")) {
+ reverse = true;
+ }
+ else {
+ parseerror(parser, "invalid attribute `%s` for enumeration", parser_tokval(parser));
+ return false;
+ }
+
+ if (!parser_next(parser) || parser->tok != '{') {
+ parseerror(parser, "expected `{` after enum attribute ");
+ return false;
+ }
+ }
+
while (true) {
if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
if (parser->tok == '}') {
vec_push(values, var);
var->cvq = CV_CONST;
var->hasvalue = true;
- var->constval.vfloat = num++;
+ /* for flagged enumerations increment in POTs of TWO */
+ var->constval.vfloat = (flag) ? (num *= 2) : (num ++);
parser_addglobal(parser, var->name, (ast_expression*)var);
if (!parser_next(parser)) {
}
}
+ /* patch them all (for reversed attribute) */
+ if (reverse) {
+ size_t i;
+ for (i = 0; i < vec_size(values); i++)
+ values[i]->constval.vfloat = vec_size(values) - i - 1;
+ }
+
if (parser->tok != '}') {
parseerror(parser, "internal error: breaking without `}`");
goto onerror;
}
}
} else {
- void *entry = (void*)var->desc;
- ast_expression *find = parser_find_var(parser, var->desc);
-
- /* aliases to aliases are also allowed */
- if (!find) {
- char *name = NULL;
- if ((find = parser_find_var(parser, (const char *)(name = util_htget(parser->aliases, var->desc)))))
- entry = (void*)name;
- }
+ ast_expression *find = parser_find_global(parser, var->desc);
if (!find) {
compile_error(parser_ctx(parser), "undeclared variable `%s` for alias `%s`", var->desc, var->name);
* add alias to aliases table and to corrector
* so corrections can apply for aliases as well.
*/
- util_htset(parser->aliases, var->name, entry);
+ util_htset(parser->aliases, var->name, find);
/*
* add to corrector so corrections can work
util_asprintf(&buffer[1], "%s_y", var->desc);
util_asprintf(&buffer[2], "%s_z", var->desc);
- util_htset(parser->aliases, me[0]->name, (void*)buffer[0]);
- util_htset(parser->aliases, me[1]->name, (void*)buffer[1]);
- util_htset(parser->aliases, me[2]->name, (void*)buffer[2]);
+ util_htset(parser->aliases, me[0]->name, parser_find_global(parser, buffer[0]));
+ util_htset(parser->aliases, me[1]->name, parser_find_global(parser, buffer[1]));
+ util_htset(parser->aliases, me[2]->name, parser_find_global(parser, buffer[2]));
+
+ mem_d(buffer[0]);
+ mem_d(buffer[1]);
+ mem_d(buffer[2]);
/*
* add to corrector so corrections can work
util_htdel(parser->aliases);
+ intrin_intrinsics_destroy();
+
mem_d(parser);
}