* parsing
*/
-bool parser_next(parser_t *parser)
+static bool parser_next(parser_t *parser)
{
/* lex_do kills the previous token */
parser->tok = lex_do(parser->lex);
char name[32];
util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
ast_value_set_name(out, name);
+ out->expression.flags |= AST_FLAG_INCLUDE_DEF;
}
return out;
}
char name[32];
util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
out = ast_value_new(parser_ctx(parser), name, TYPE_STRING);
+ out->expression.flags |= AST_FLAG_INCLUDE_DEF;
} else
out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING);
out->cvq = CV_CONST;
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))));
+ out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) << (unsigned int)(ConstF(1))));
else
- out = (ast_expression*)parser_const_float(parser, (double)((int)(ConstF(0)) >> (int)(ConstF(1))));
+ out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) >> (unsigned int)(ConstF(1))));
break;
}
case opid3('<','<','='):
static bool parse_return(parser_t *parser, ast_block *block, ast_expression **out)
{
- ast_expression *exp = NULL;
- ast_return *ret = NULL;
+ ast_expression *exp = NULL;
+ ast_expression *var = NULL;
+ ast_return *ret = NULL;
+ ast_value *retval = parser->function->return_value;
ast_value *expected = parser->function->vtype;
lex_ctx ctx = parser_ctx(parser);
return false;
}
+ /* return assignments */
+ if (parser->tok == '=') {
+ if (!OPTS_FLAG(RETURN_ASSIGNMENTS)) {
+ parseerror(parser, "return assignments not activated, try using -freturn-assigments");
+ return false;
+ }
+
+ if (type_store_instr[expected->expression.next->vtype] == VINSTR_END) {
+ char ty1[1024];
+ ast_type_to_string(expected->expression.next, ty1, sizeof(ty1));
+ parseerror(parser, "invalid return type: `%s'", ty1);
+ return false;
+ }
+
+ if (!parser_next(parser)) {
+ parseerror(parser, "expected return assignment expression");
+ return false;
+ }
+
+ if (!(exp = parse_expression_leave(parser, false, false, false)))
+ return false;
+
+ /* prepare the return value */
+ if (!retval) {
+ retval = ast_value_new(ctx, "#LOCAL_RETURN", TYPE_VOID);
+ ast_type_adopt(retval, expected->expression.next);
+ parser->function->return_value = retval;
+ }
+
+ if (!ast_compare_type(exp, (ast_expression*)retval)) {
+ char ty1[1024], ty2[1024];
+ ast_type_to_string(exp, ty1, sizeof(ty1));
+ ast_type_to_string(&retval->expression, ty2, sizeof(ty2));
+ parseerror(parser, "invalid type for return value: `%s', expected `%s'", ty1, ty2);
+ }
+
+ /* store to 'return' local variable */
+ var = (ast_expression*)ast_store_new(
+ ctx,
+ type_store_instr[expected->expression.next->vtype],
+ (ast_expression*)retval, exp);
+
+ if (!var) {
+ ast_unref(exp);
+ return false;
+ }
+
+ if (parser->tok != ';')
+ parseerror(parser, "missing semicolon after return assignment");
+ else if (!parser_next(parser))
+ parseerror(parser, "parse error after return assignment");
+
+ *out = var;
+ return true;
+ }
+
if (parser->tok != ';') {
exp = parse_expression(parser, false, false);
if (!exp)
} else {
if (!parser_next(parser))
parseerror(parser, "parse error");
- if (expected->expression.next->vtype != TYPE_VOID) {
+
+ if (!retval && expected->expression.next->vtype != TYPE_VOID)
+ {
(void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value");
}
- ret = ast_return_new(ctx, NULL);
+ ret = ast_return_new(ctx, (ast_expression*)retval);
}
*out = (ast_expression*)ret;
return true;
}
return parse_typedef(parser);
}
- parseerror(parser, "Unexpected keyword");
+ parseerror(parser, "Unexpected keyword: `%s'", parser_tokval(parser));
return false;
}
else if (parser->tok == '{')
}
vec_push(func->blocks, block);
+
parser->function = old;
if (!parser_leaveblock(parser))
/* for the sake of less code we parse-in in this function */
if (!parser_next(parser)) {
+ ast_delete(var);
parseerror(parser, "expected parameter list");
return NULL;
}
/* parse on */
if (!parser_next(parser)) {
ast_delete(var);
+ mem_d(name);
parseerror(parser, "error after variable or field declaration");
return NULL;
}
if (parser->tok == '[') {
wasarray = true;
var = parse_arraysize(parser, var);
- if (!var)
+ if (!var) {
+ if (name) mem_d(name);
return NULL;
+ }
}
/* This is the point where we can turn it into a field */
while (parser->tok == '(') {
var = parse_parameter_list(parser, var);
if (!var) {
- if (name)
- mem_d((void*)name);
+ if (name) mem_d(name);
return NULL;
}
}
if (name) {
if (!ast_value_set_name(var, name)) {
ast_delete(var);
+ mem_d(name);
parseerror(parser, "internal error: failed to set name");
return NULL;
}
/* free the name, ast_value_set_name duplicates */
- mem_d((void*)name);
+ mem_d(name);
}
return var;
}
vec_free(sy.out);
vec_free(sy.ops);
+ vec_free(sy.argc);
var->cvq = cvq;
}
}
return parser;
}
-bool parser_compile(parser_t *parser)
+static bool parser_compile(parser_t *parser)
{
/* initial lexer/parser state */
parser->lex->flags.noops = true;