mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-03-21 10:21:03 +00:00
Implemented __builtin_mod, and % operator. Added floor builtin to the standalone executor. Mod works so long as the compiler can find a suitable definition of "float floor(float)", otherwise it prints a diagnostic and gives up (original id1 Quake had floor so we can depend on it).
This commit is contained in:
parent
b971ddec3a
commit
f19adcd1b3
3 changed files with 114 additions and 2 deletions
13
exec.c
13
exec.c
|
@ -825,6 +825,16 @@ static int qc_strcmp(qc_program *prog)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int qc_floor(qc_program *prog)
|
||||
{
|
||||
qcany *num, out;
|
||||
CheckArgs(1);
|
||||
num = GetArg(0);
|
||||
out._float = floor(num->_float);
|
||||
Return(out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static prog_builtin qc_builtins[] = {
|
||||
NULL,
|
||||
&qc_print, /* 1 */
|
||||
|
@ -839,7 +849,8 @@ static prog_builtin qc_builtins[] = {
|
|||
&qc_strcat, /* 10 */
|
||||
&qc_strcmp, /* 11 */
|
||||
&qc_normalize, /* 12 */
|
||||
&qc_sqrt /* 13 */
|
||||
&qc_sqrt, /* 13 */
|
||||
&qc_floor /* 14 */
|
||||
};
|
||||
static size_t qc_builtins_count = sizeof(qc_builtins) / sizeof(qc_builtins[0]);
|
||||
|
||||
|
|
6
lexer.c
6
lexer.c
|
@ -1361,6 +1361,12 @@ int lex_do(lex_file *lex)
|
|||
return (lex->tok.ttype = TOKEN_OPERATOR);
|
||||
}
|
||||
|
||||
if (ch == '%') {
|
||||
lex_tokench(lex, ch);
|
||||
lex_endtoken(lex);
|
||||
return (lex->tok.ttype = TOKEN_OPERATOR);
|
||||
}
|
||||
|
||||
if (isident_start(ch))
|
||||
{
|
||||
const char *v;
|
||||
|
|
97
parser.c
97
parser.c
|
@ -120,8 +120,10 @@ static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool
|
|||
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 ast_expression *parser_builtin_pow(parser_t *);
|
||||
static ast_expression *parser_builtin_exp(parser_t *);
|
||||
static ast_expression *parser_builtin_mod(parser_t *);
|
||||
|
||||
static void parseerror(parser_t *parser, const char *fmt, ...)
|
||||
{
|
||||
|
@ -964,10 +966,35 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
|
|||
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 = parser_builtin_mod(parser);
|
||||
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)) {
|
||||
|
@ -1858,6 +1885,8 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
|
|||
var = parser_builtin_pow(parser);
|
||||
if (!strcmp(parser_tokval(parser), "__builtin_exp"))
|
||||
var = parser_builtin_exp(parser);
|
||||
if (!strcmp(parser_tokval(parser), "__builtin_mod"))
|
||||
var = parser_builtin_mod(parser);
|
||||
|
||||
if (!var) {
|
||||
char *correct = NULL;
|
||||
|
@ -3501,6 +3530,72 @@ static ast_expression *parser_builtin_exp(parser_t *parser) {
|
|||
return (ast_expression*)exp_func_val;
|
||||
}
|
||||
|
||||
static ast_expression *parser_builtin_mod(parser_t *parser) {
|
||||
/*
|
||||
* float __builtin_mod(float x, float y) {
|
||||
* return x - y * floor(x / y);
|
||||
* }
|
||||
*/
|
||||
static ast_value *mod_func_val = NULL;
|
||||
static ast_expression *mod_floor = NULL;
|
||||
|
||||
if (!mod_floor) {
|
||||
if (!(mod_floor = parser_find_global(parser, "floor"))) {
|
||||
parseerror(parser, "internal error: no suitable definition found for `floor` (required for % and __builtin_mod)");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mod_func_val) {
|
||||
ast_value *mod_args[2];
|
||||
ast_function *mod_func = NULL;
|
||||
ast_block *mod_body = ast_block_new (parser_ctx(parser));
|
||||
ast_call *mod_call = ast_call_new (parser_ctx(parser), mod_floor);
|
||||
mod_func_val = ast_value_new (parser_ctx(parser), "__builtin_mod", TYPE_FUNCTION);
|
||||
mod_func_val->expression.next = (ast_expression*)ast_value_new(parser_ctx(parser), "<float>", TYPE_FLOAT);
|
||||
mod_func = ast_function_new(parser_ctx(parser), "__builtin_mod", mod_func_val);
|
||||
mod_args[0] = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT);
|
||||
mod_args[1] = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT);
|
||||
|
||||
/* floor(x/y) */
|
||||
vec_push(mod_call->params,
|
||||
(ast_expression*)ast_binary_new(
|
||||
parser_ctx(parser),
|
||||
INSTR_DIV_F,
|
||||
(ast_expression*)mod_args[0],
|
||||
(ast_expression*)mod_args[1]
|
||||
)
|
||||
);
|
||||
|
||||
vec_push(mod_body->exprs,
|
||||
(ast_expression*)ast_return_new(
|
||||
parser_ctx(parser),
|
||||
(ast_expression*)ast_binary_new(
|
||||
parser_ctx(parser),
|
||||
INSTR_SUB_F,
|
||||
(ast_expression*)mod_args[0],
|
||||
(ast_expression*)ast_binary_new(
|
||||
parser_ctx(parser),
|
||||
INSTR_MUL_F,
|
||||
(ast_expression*)mod_args[1],
|
||||
(ast_expression*)mod_call
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
vec_push(mod_func_val->expression.params, mod_args[0]);
|
||||
vec_push(mod_func_val->expression.params, mod_args[1]);
|
||||
|
||||
vec_push(mod_func->blocks, mod_body);
|
||||
|
||||
vec_push(parser->functions, mod_func);
|
||||
vec_push(parser->globals, (ast_expression*)mod_func_val);
|
||||
}
|
||||
|
||||
return (ast_expression*)mod_func_val;
|
||||
}
|
||||
|
||||
/* parse computed goto sides */
|
||||
static ast_expression *parse_goto_computed(parser_t *parser, ast_expression **side) {
|
||||
ast_expression *on_true;
|
||||
|
|
Loading…
Reference in a new issue