Implemented computed goto + added goto test for testsuite (tests both normal and computed goto statements).

This commit is contained in:
Dale Weiler 2013-01-02 21:32:57 +00:00
parent 467a4740da
commit a421d9a33b
3 changed files with 103 additions and 7 deletions

View file

@ -300,6 +300,17 @@ static ast_expression* parser_find_field(parser_t *parser, const char *name)
return ( ast_expression*)util_htget(parser->htfields, name);
}
static ast_expression* parser_find_label(parser_t *parser, const char *name) {
size_t i;
if (!parser->labels)
return NULL;
for(i = 0; i < vec_size(parser->labels); i++)
if (!strcmp(parser->labels[i]->name, name))
return (ast_expression*)parser->labels[i];
return NULL;
}
static ast_expression* parser_find_global(parser_t *parser, const char *name)
{
return (ast_expression*)util_htget(parser->htglobals, name);
@ -1573,18 +1584,19 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
parseerror(parser, "namespace for member not found");
goto onerr;
}
else
var = parser_find_var(parser, parser_tokval(parser));
else if (!(var = parser_find_var(parser, parser_tokval(parser))))
var = (ast_expression*)parser_find_label(parser, parser_tokval(parser));
} else {
var = parser_find_var(parser, parser_tokval(parser));
if (!var)
var = parser_find_field(parser, parser_tokval(parser));
if (!var)
var = parser_find_label(parser, parser_tokval(parser));
}
if (!var) {
/* intrinsics */
if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) {
var = (ast_expression*)intrinsic_debug_typestring;
}
else
{
@ -2957,16 +2969,54 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression *
return true;
}
/* parse computed goto sides */
static ast_expression *parse_goto_computed(parser_t *parser, ast_expression *side) {
ast_expression *on_true;
ast_expression *on_false;
if (!side)
return NULL;
if (ast_istype(side, ast_ternary)) {
on_true = parse_goto_computed(parser, ((ast_ternary*)side)->on_true);
on_false = parse_goto_computed(parser, ((ast_ternary*)side)->on_false);
return (ast_expression*)ast_ifthen_new(parser_ctx(parser), ((ast_ternary*)side)->cond, on_true, on_false);
} else if (ast_istype(side, ast_label)) {
ast_goto *gt = ast_goto_new(parser_ctx(parser), ((ast_label*)side)->name);
ast_goto_set_label(gt, ((ast_label*)side));
return (ast_expression*)gt;
}
return NULL;
}
static bool parse_goto(parser_t *parser, ast_expression **out)
{
size_t i;
ast_goto *gt;
ast_goto *gt = NULL;
if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
parseerror(parser, "expected label name after `goto`");
if (!parser_next(parser))
return false;
if (parser->tok != TOKEN_IDENT) {
ast_expression *expression;
/* could be an expression i.e computed goto :-) */
if (parser->tok != '(') {
parseerror(parser, "expected label name after `goto`");
return false;
}
/* failed to parse expression for goto */
if (!(expression = parse_expression(parser, false)))
return false;
if (!(*out = parse_goto_computed(parser, expression)))
return false;
return true;
}
/* not computed goto */
gt = ast_goto_new(parser_ctx(parser), parser_tokval(parser));
for (i = 0; i < vec_size(parser->labels); ++i) {
@ -2979,7 +3029,7 @@ static bool parse_goto(parser_t *parser, ast_expression **out)
vec_push(parser->gotos, gt);
if (!parser_next(parser) || parser->tok != ';') {
parseerror(parser, "semicolon expected after goto label");
parseerror(parser, "semicolon expected after goto label got");
return false;
}
if (!parser_next(parser)) {

34
tests/goto.qc Normal file
View file

@ -0,0 +1,34 @@
void(string, ...) print = #1;
// correct execution order:
// label_3
// label_2
// label_4
// label_3
// label_1
// label_5
void main() {
float x = 1;
float y = 2;
goto label_3;
:label_1; print("label_1", "\n"); goto label_5;
:label_2; print("label_2", "\n"); goto label_4;
:label_3; print("label_3", "\n");
// will goto label_2
goto (x == y) ? label_1 : label_2;
:label_4; print("label_4", "\n");
{
x = 1;
y = 1;
// will goto label_1
// then goes label_5
goto label_3;
}
:label_5; print("label_5", "\n");
}

12
tests/goto.tmpl Normal file
View file

@ -0,0 +1,12 @@
I: goto.qc
D: test goto (both normal and computed)
T: -execute
C: -std=gmqcc
F: goto failed
S: goto worked
M: label_3
M: label_2
M: label_4
M: label_3
M: label_1
M: label_5