void ast_ternary_delete(ast_ternary *self)
{
- ast_unref(self->cond);
- ast_unref(self->on_true);
- ast_unref(self->on_false);
+ /* the if()s are only there because computed-gotos can set them
+ * to NULL
+ */
+ if (self->cond) ast_unref(self->cond);
+ if (self->on_true) ast_unref(self->on_true);
+ if (self->on_false) ast_unref(self->on_false);
ast_expression_delete((ast_expression*)self);
mem_d(self);
}
{
ppmacro *macro;
bool wasnot = false;
+ bool wasneg = false;
if (!ftepp_skipspace(ftepp))
return false;
return false;
}
+ if (ftepp->token == TOKEN_OPERATOR && !strcmp(ftepp_tokval(ftepp), "-"))
+ {
+ wasneg = true;
+ ftepp_next(ftepp);
+ if (!ftepp_skipspace(ftepp))
+ return false;
+ }
+
switch (ftepp->token) {
case TOKEN_IDENT:
case TOKEN_TYPENAME:
}
break;
case TOKEN_STRINGCONST:
+ *value_out = 0;
*out = false;
break;
case TOKEN_INTCONST:
default:
ftepp_error(ftepp, "junk in #if: `%s` ...", ftepp_tokval(ftepp));
+ if (opts.debug)
+ ftepp_error(ftepp, "internal: token %i\n", ftepp->token);
return false;
}
+ if (wasneg)
+ *value_out = -*value_out;
if (wasnot) {
*out = !*out;
*value_out = (*out ? 1 : 0);
lex_tokench(lex, nextch);
lex_tokench(lex, thirdch);
}
+ }
+ else if (lex->flags.preprocessing &&
+ ch == '-' && isdigit(nextch))
+ {
+ lex->tok.ttype = lex_finish_digit(lex, nextch);
+ if (lex->tok.ttype == TOKEN_INTCONST)
+ lex->tok.constval.i = -lex->tok.constval.i;
+ else
+ lex->tok.constval.f = -lex->tok.constval.f;
+ lex_endtoken(lex);
+ return lex->tok.ttype;
} else
lex_ungetch(lex, nextch);
}
/* parse computed goto sides */
-static ast_expression *parse_goto_computed(parser_t *parser, ast_expression *side) {
+static ast_expression *parse_goto_computed(parser_t *parser, ast_expression **side) {
ast_expression *on_true;
ast_expression *on_false;
+ ast_expression *cond;
- if (!side)
+ if (!*side)
return NULL;
- if (ast_istype(side, ast_ternary)) {
- on_true = parse_goto_computed(parser, ((ast_ternary*)side)->on_true);
- on_false = parse_goto_computed(parser, ((ast_ternary*)side)->on_false);
+ if (ast_istype(*side, ast_ternary)) {
+ ast_ternary *tern = (ast_ternary*)*side;
+ on_true = parse_goto_computed(parser, &tern->on_true);
+ on_false = parse_goto_computed(parser, &tern->on_false);
if (!on_true || !on_false) {
parseerror(parser, "expected label or expression in ternary");
- if (((ast_ternary*)side)->on_false) ast_unref(((ast_ternary*)side)->on_false);
- if (((ast_ternary*)side)->on_true) ast_unref(((ast_ternary*)side)->on_true);
+ if (on_true) ast_unref(on_true);
+ if (on_false) ast_unref(on_false);
return NULL;
}
- return (ast_expression*)ast_ifthen_new(parser_ctx(parser), ((ast_ternary*)side)->cond, on_true, on_false);
- } else if (ast_istype(side, ast_label)) {
- ast_goto *gt = ast_goto_new(parser_ctx(parser), ((ast_label*)side)->name);
- ast_goto_set_label(gt, ((ast_label*)side));
+ cond = tern->cond;
+ tern->cond = NULL;
+ ast_delete(tern);
+ *side = NULL;
+ return (ast_expression*)ast_ifthen_new(parser_ctx(parser), cond, on_true, on_false);
+ } else if (ast_istype(*side, ast_label)) {
+ ast_goto *gt = ast_goto_new(parser_ctx(parser), ((ast_label*)*side)->name);
+ ast_goto_set_label(gt, ((ast_label*)*side));
+ *side = NULL;
return (ast_expression*)gt;
}
return NULL;
/* failed to parse expression for goto */
if (!(expression = parse_expression(parser, false, true)) ||
- !(*out = parse_goto_computed(parser, expression))) {
+ !(*out = parse_goto_computed(parser, &expression))) {
parseerror(parser, "invalid goto expression");
ast_unref(expression);
return false;