[qfcc] Implement goto

It's just too useful when used correctly.
This commit is contained in:
Bill Currie 2020-03-11 12:53:40 +09:00
parent 4a8854d9ed
commit 813319efc2
3 changed files with 19 additions and 7 deletions

View file

@ -353,6 +353,7 @@ static keyword_t obj_keywords[] = {
// make the language features available to traditional code. // make the language features available to traditional code.
static keyword_t at_keywords[] = { static keyword_t at_keywords[] = {
{"for", FOR }, {"for", FOR },
{"goto", GOTO },
{"break", BREAK }, {"break", BREAK },
{"continue", CONTINUE}, {"continue", CONTINUE},
{"switch", SWITCH }, {"switch", SWITCH },

View file

@ -145,8 +145,8 @@ int yylex (void);
%token <expr> VALUE STRING %token <expr> VALUE STRING
%token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELLIPSIS %token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELLIPSIS
%token NIL IFBE IFB IFAE IFA SWITCH CASE DEFAULT ENUM TYPEDEF %token NIL IFBE IFB IFAE IFA GOTO SWITCH CASE DEFAULT ENUM
%token ARGS EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT %token ARGS TYPEDEF EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT
%token <op> STRUCT %token <op> STRUCT
%token <type> TYPE %token <type> TYPE
%token <symbol> OBJECT TYPE_NAME %token <symbol> OBJECT TYPE_NAME
@ -1310,6 +1310,11 @@ statement
switch_block = $5; switch_block = $5;
break_label = $2; break_label = $2;
} }
| GOTO NAME
{
expr_t *label = named_label_expr ($2);
$$ = goto_expr (label);
}
| IF not '(' texpr ')' statement %prec IFX | IF not '(' texpr ')' statement %prec IFX
{ {
$$ = build_if_statement ($2, $4, $6, 0, 0); $$ = build_if_statement ($2, $4, $6, 0, 0);

View file

@ -1551,7 +1551,7 @@ remove_label_from_dest (ex_label_t *label)
sblock_t *sblock; sblock_t *sblock;
ex_label_t **l; ex_label_t **l;
if (!label) if (!label || !label->dest)
return; return;
debug (0, "dropping deceased label %s", label->name); debug (0, "dropping deceased label %s", label->name);
@ -1588,14 +1588,20 @@ thread_jumps (sblock_t *blocks)
if (!sblock->statements) if (!sblock->statements)
continue; continue;
s = (statement_t *) sblock->tail; s = (statement_t *) sblock->tail;
if (statement_is_goto (s)) if (statement_is_goto (s)) {
label = &s->opa->o.label; label = &s->opa->o.label;
else if (statement_is_cond (s)) if (!(*label)->dest && s->opa->expr) {
error (s->opa->expr, "undefined label `%s'", (*label)->name);
s->opa->expr = 0;
}
} else if (statement_is_cond (s)) {
label = &s->opb->o.label; label = &s->opb->o.label;
else } else {
continue; continue;
}
for (l = *label; for (l = *label;
l->dest->statements && statement_is_goto (l->dest->statements); l->dest && l->dest->statements
&& statement_is_goto (l->dest->statements);
l = l->dest->statements->opa->o.label) { l = l->dest->statements->opa->o.label) {
} }
if (l != *label) { if (l != *label) {