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 void parseerror(parser_t *parser, const char *fmt, ...)
{
}
if (!strcmp(parser_tokval(parser), "__builtin_pow"))
var = parser_builtin_pow(parser);
+ if (!strcmp(parser_tokval(parser), "__builtin_exp"))
+ var = parser_builtin_exp(parser);
if (!var) {
char *correct = NULL;
* float value = 1.0f;
* while (y > 0) {
* while (!(y&1)) {
- * y *= 2;
+ * y *= 0.25f;
* x *= x;
* }
- * y = y - 1;
- * value = x * value;
+ * y--;
+ * value *= x;
* }
* return value;
* }
return (ast_expression*)pow_func_val;
}
+#ifndef M_E
+#define M_E 2.71828182845905
+#endif
+static ast_expression *parser_builtin_exp(parser_t *parser) {
+ /*
+ * float __builtin_exp(float x) {
+ * return __builtin_exp(E, x);
+ * }
+ */
+ static ast_value *exp_func_val = NULL;
+
+ if (!exp_func_val) {
+ ast_function *exp_func = NULL;
+ ast_value *arg = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT);
+ ast_block *exp_body = ast_block_new (parser_ctx(parser));
+ ast_call *exp_call = ast_call_new (parser_ctx(parser), parser_builtin_pow(parser));
+ exp_func_val = ast_value_new (parser_ctx(parser), "__builtin_exp", TYPE_FUNCTION);
+ exp_func_val->expression.next = (ast_expression*)ast_value_new(parser_ctx(parser), "<float>", TYPE_FLOAT);
+ exp_func = ast_function_new(parser_ctx(parser), "__builtin_exp", exp_func_val);
+
+ vec_push(exp_call->params, (ast_expression*)parser_const_float(parser, M_E));
+ vec_push(exp_call->params, (ast_expression*)arg);
+
+ vec_push(exp_body->exprs,
+ (ast_expression*)ast_return_new(
+ parser_ctx(parser),
+ (ast_expression*)exp_call
+ )
+ );
+
+ vec_push(exp_func_val->expression.params, arg);
+ vec_push(exp_func->blocks, exp_body);
+
+ vec_push(parser->functions, exp_func);
+ vec_push(parser->globals, (ast_expression*)exp_func_val);
+ }
+
+ return (ast_expression*)exp_func_val;
+}
+
/* parse computed goto sides */
static ast_expression *parse_goto_computed(parser_t *parser, ast_expression **side) {
ast_expression *on_true;
static bool parse_enum(parser_t *parser)
{
+ bool flag = 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 || strcmp(parser_tokval(parser), "flag")) {
+ parseerror(parser, "expected `flag` after enumeration attribute ':'");
+ return false;
+ }
+
+ if (!parser_next(parser) || parser->tok != '{') {
+ parseerror(parser, "expected `{` after enum attribute `flag`");
+ return false;
+ }
+
+ /* flagged enumeration start from 1 */
+ num = 1;
+ flag = true;
+ }
+
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);