Implement "if not (foo)" syntax.

It is syntactic sugar for if (!(foo)), but is useful for avoiding
inconsistencies between such things as if (string) and if (!string), even
though qcc can't parse if not (string). It also makes for easier to read
code when the logic in the condition is complex.
This commit is contained in:
Bill Currie 2012-12-20 10:02:00 +09:00
parent 77337e2402
commit 8d34d33055
5 changed files with 24 additions and 12 deletions

View file

@ -598,7 +598,8 @@ expr_t *incop_expr (int op, expr_t *e, int postop);
expr_t *array_expr (expr_t *array, expr_t *index);
expr_t *pointer_expr (expr_t *pointer);
expr_t *address_expr (expr_t *e1, expr_t *e2, struct type_s *t);
expr_t *build_if_statement (expr_t *test, expr_t *s1, expr_t *els, expr_t *s2);
expr_t *build_if_statement (int not, expr_t *test, expr_t *s1, expr_t *els,
expr_t *s2);
expr_t *build_while_statement (expr_t *test, expr_t *statement,
expr_t *break_label, expr_t *continue_label);
expr_t *build_do_while_statement (expr_t *statement, expr_t *test,

View file

@ -2284,7 +2284,7 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
}
expr_t *
build_if_statement (expr_t *test, expr_t *s1, expr_t *els, expr_t *s2)
build_if_statement (int not, expr_t *test, expr_t *s1, expr_t *els, expr_t *s2)
{
int line = pr.source_line;
string_t file = pr.source_file;
@ -2299,8 +2299,13 @@ build_if_statement (expr_t *test, expr_t *s1, expr_t *els, expr_t *s2)
test = convert_bool (test, 1);
if (test->type != ex_error) {
backpatch (test->e.bool.true_list, tl);
backpatch (test->e.bool.false_list, fl);
if (not) {
backpatch (test->e.bool.true_list, fl);
backpatch (test->e.bool.false_list, tl);
} else {
backpatch (test->e.bool.true_list, tl);
backpatch (test->e.bool.false_list, fl);
}
append_expr (test->e.bool.e, tl);
append_expr (if_expr, test);
}

View file

@ -319,6 +319,7 @@ static keyword_t at_keywords[] = {
{"static", STATIC },
{"sizeof", SIZEOF },
{"nosave", NOSAVE },
{"not", NOT },
};
// These keywords require the QuakeForge VM to be of any use. ie, they cannot

View file

@ -145,7 +145,7 @@ int yylex (void);
%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
%token ARGS EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT
%token <op> STRUCT
%token <type> TYPE
%token <symbol> OBJECT TYPE_NAME
@ -205,7 +205,7 @@ int yylex (void);
%type <protocol> protocol_name
%type <methodlist> methodprotolist methodprotolist2
%type <symtab> ivar_decl_list
%type <op> ci
%type <op> ci not
%{
@ -1149,13 +1149,13 @@ statement
switch_block = $5;
break_label = $2;
}
| IF '(' texpr ')' statement %prec IFX
| IF not '(' texpr ')' statement %prec IFX
{
$$ = build_if_statement ($3, $5, 0, 0);
$$ = build_if_statement ($2, $4, $6, 0, 0);
}
| IF '(' texpr ')' statement else statement
| IF not '(' texpr ')' statement else statement
{
$$ = build_if_statement ($3, $5, $6, $7);
$$ = build_if_statement ($2, $4, $6, $7, $8);
}
| FOR break_label continue_label
'(' opt_expr ';' opt_expr ';' opt_expr ')' statement
@ -1184,6 +1184,11 @@ statement
}
;
not
: NOT { $$ = 1; }
| /* empty */ { $$ = 0; }
;
else
: ELSE
{

View file

@ -354,11 +354,11 @@ statement
| compound_statement
| IF expression THEN statement else statement
{
$$ = build_if_statement ($2, $4, $5, $6);
$$ = build_if_statement (0, $2, $4, $5, $6);
}
| IF expression THEN statement %prec IFX
{
$$ = build_if_statement ($2, $4, 0, 0);
$$ = build_if_statement (0, $2, $4, 0, 0);
}
| WHILE expression DO statement
{