mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-13 00:24:12 +00:00
[qfcc] Implement goto
It's just too useful when used correctly.
This commit is contained in:
parent
4a8854d9ed
commit
813319efc2
3 changed files with 19 additions and 7 deletions
|
@ -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 },
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue