diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index 353191593..9d5c5a1b9 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -353,6 +353,7 @@ static keyword_t obj_keywords[] = { // make the language features available to traditional code. static keyword_t at_keywords[] = { {"for", FOR }, + {"goto", GOTO }, {"break", BREAK }, {"continue", CONTINUE}, {"switch", SWITCH }, diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 3e5079313..27423d4ef 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -145,8 +145,8 @@ int yylex (void); %token VALUE STRING %token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELLIPSIS -%token NIL IFBE IFB IFAE IFA SWITCH CASE DEFAULT ENUM TYPEDEF -%token ARGS EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT +%token NIL IFBE IFB IFAE IFA GOTO SWITCH CASE DEFAULT ENUM +%token ARGS TYPEDEF EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT %token STRUCT %token TYPE %token OBJECT TYPE_NAME @@ -1310,6 +1310,11 @@ statement switch_block = $5; break_label = $2; } + | GOTO NAME + { + expr_t *label = named_label_expr ($2); + $$ = goto_expr (label); + } | IF not '(' texpr ')' statement %prec IFX { $$ = build_if_statement ($2, $4, $6, 0, 0); diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index e156efd1a..42a5494e8 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1551,7 +1551,7 @@ remove_label_from_dest (ex_label_t *label) sblock_t *sblock; ex_label_t **l; - if (!label) + if (!label || !label->dest) return; debug (0, "dropping deceased label %s", label->name); @@ -1588,14 +1588,20 @@ thread_jumps (sblock_t *blocks) if (!sblock->statements) continue; s = (statement_t *) sblock->tail; - if (statement_is_goto (s)) + if (statement_is_goto (s)) { 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; - else + } else { continue; + } 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) { } if (l != *label) {