From 133ce647fb4d675ae1b846ad825b206876d50c85 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 24 Oct 2001 18:57:29 +0000 Subject: [PATCH] implement break and continue. only loops covered for now, but that's because switch isn't implemented yet --- tools/qfcc/TODO | 2 +- tools/qfcc/source/qc-lex.l | 2 + tools/qfcc/source/qc-parse.y | 91 ++++++++++++++++++++++++++---------- 3 files changed, 69 insertions(+), 26 deletions(-) diff --git a/tools/qfcc/TODO b/tools/qfcc/TODO index aef6a595c..d141786fb 100644 --- a/tools/qfcc/TODO +++ b/tools/qfcc/TODO @@ -14,7 +14,7 @@ X move the chained funcion support out of emit_function_expr into X pre- and post- increment operators (++ and --) I gut out old parser o switch/case, for any type -o break/continue keywords for switch() and for(;;) +X break/continue keywords for switch() and for(;;) o quaternion type. Tricky: requires 4 word args/return o CSE optimisations X full scoping diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index 01593a22d..7c0b17334 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -220,6 +220,8 @@ static keyword_t keywords[] = { {"if", IF, 0, PROG_ID_VERSION}, {"else", ELSE, 0, PROG_ID_VERSION}, {"for", FOR, 0, PROG_ID_VERSION}, + {"break", BREAK, 0, PROG_ID_VERSION}, + {"continue", CONTINUE, 0, PROG_ID_VERSION}, {"NIL", NIL, 0, PROG_ID_VERSION}, }; diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 4670d0842..0904e4cc1 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -103,13 +103,14 @@ typedef struct { %token VECTOR_VAL %token QUATERNION_VAL -%token LOCAL RETURN WHILE DO IF ELSE FOR ELIPSIS NIL +%token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELIPSIS NIL %token TYPE %type type maybe_func %type param param_list def_item def_list def_name %type const opt_expr expr arg_list %type statement statements statement_block +%type break_label continue_label %type begin_function %type save_inits @@ -122,6 +123,8 @@ def_t *current_def; def_t param_scope; function_t *current_func; expr_t *local_expr; +expr_t *break_label; +expr_t *continue_label; def_t *pr_scope; // the function being parsed, or NULL string_t s_file; // filename for function definition @@ -404,38 +407,59 @@ statement { $$ = return_expr (current_func, 0); } - | WHILE '(' expr ')' save_inits statement + | BREAK ';' + { + if (break_label) + $$ = new_unary_expr ('g', break_label); + else + $$ = error (0, "break outside of loop or switch"); + } + | CONTINUE ';' + { + if (continue_label) + $$ = new_unary_expr ('g', continue_label); + else + $$ = error (0, "continue outside of loop"); + } + | WHILE break_label continue_label '(' expr ')' save_inits statement { expr_t *l1 = new_label_expr (); - expr_t *l2 = new_label_expr (); + expr_t *l2 = break_label; expr_t *e; - restore_local_inits ($5); - free_local_inits ($5); + restore_local_inits ($7); + free_local_inits ($7); $$ = new_block_expr (); - e = new_binary_expr ('n', test_expr ($3, 1), l2); - e->line = $3->line; - e->file = $3->file; + e = new_binary_expr ('n', test_expr ($5, 1), l2); + e->line = $5->line; + e->file = $5->file; append_expr ($$, e); append_expr ($$, l1); - append_expr ($$, $6); - e = new_binary_expr ('i', test_expr ($3, 1), l1); - e->line = $3->line; - e->file = $3->file; + append_expr ($$, $8); + append_expr ($$, continue_label); + e = new_binary_expr ('i', test_expr ($5, 1), l1); + e->line = $5->line; + e->file = $5->file; append_expr ($$, e); append_expr ($$, l2); + break_label = $2; + continue_label = $3; } - | DO statement WHILE '(' expr ')' ';' + | DO break_label continue_label statement WHILE '(' expr ')' ';' { expr_t *l1 = new_label_expr (); $$ = new_block_expr (); append_expr ($$, l1); - append_expr ($$, $2); - append_expr ($$, new_binary_expr ('i', test_expr ($5, 1), l1)); + append_expr ($$, $4); + append_expr ($$, continue_label); + append_expr ($$, new_binary_expr ('i', test_expr ($7, 1), l1)); + append_expr ($$, break_label); + break_label = $2; + continue_label = $3; } | LOCAL type { @@ -503,25 +527,28 @@ statement free_local_inits (else_ini); free_local_inits ($8); } - | FOR '(' opt_expr ';' opt_expr ';' opt_expr ')' save_inits statement + | FOR break_label continue_label '(' opt_expr ';' opt_expr ';' opt_expr ')' save_inits statement { expr_t *l1 = new_label_expr (); - expr_t *l2 = new_label_expr (); + expr_t *l2 = break_label; - restore_local_inits ($9); - free_local_inits ($9); + restore_local_inits ($11); + free_local_inits ($11); $$ = new_block_expr (); - append_expr ($$, $3); - if ($5) - append_expr ($$, new_binary_expr ('n', test_expr ($5, 1), l2)); + append_expr ($$, $5); + if ($7) + append_expr ($$, new_binary_expr ('n', test_expr ($7, 1), l2)); append_expr ($$, l1); - append_expr ($$, $10); - append_expr ($$, $7); + append_expr ($$, $12); + append_expr ($$, continue_label); + append_expr ($$, $9); if ($5) - append_expr ($$, new_binary_expr ('i', test_expr ($5, 1), l1)); + append_expr ($$, new_binary_expr ('i', test_expr ($7, 1), l1)); append_expr ($$, l2); + break_label = $2; + continue_label = $3; } | expr ';' { @@ -529,6 +556,20 @@ statement } ; +break_label + : /* empty */ + { + $$ = break_label; + break_label = new_label_expr (); + } + +continue_label + : /* empty */ + { + $$ = continue_label; + continue_label = new_label_expr (); + } + save_inits : /* empty */ {