static AST ifstmt() { Token *t = &tok; AST a=0; AST a1=0,a2=0,a3=0; if (t->sym == tIF) { gettoken(); if (t->sym == '(') { gettoken(); a1 = bexpr(); if (t->sym == ')') gettoken(); else parse_error("expected )"); a2 = stmt(); if (t->sym == tELSE) { /* else is optional */ gettoken(); a3 = stmt(); } } else { parse_error("expected ("); } a = make_AST_if(a1,a2,a3); } else { parse_error("expected if"); skiptoken(';'); } return a; }
expr *evaluate(scanner sc, void *scprivate, struct tokenval *tv, int *fwref, int critical, struct eval_hints *hints) { expr *e; expr *f = NULL; hint = hints; if (hint) hint->type = EAH_NOHINT; if (critical & CRITICAL) { critical &= ~CRITICAL; bexpr = rexp0; } else bexpr = expr0; scan = sc; scpriv = scprivate; tokval = tv; opflags = fwref; if (tokval->t_type == TOKEN_INVALID) i = scan(scpriv, tokval); else i = tokval->t_type; while (ntempexprs) /* initialize temporary storage */ nasm_free(tempexprs[--ntempexprs]); e = bexpr(critical); if (!e) return NULL; if (i == TOKEN_WRT) { i = scan(scpriv, tokval); /* eat the WRT */ f = expr6(critical); if (!f) return NULL; } e = scalar_mult(e, 1L, false); /* strip far-absolute segment part */ if (f) { expr *g; if (is_just_unknown(f)) g = unknown_expr(); else { int64_t value; begintemp(); if (!is_reloc(f)) { nasm_error(ERR_NONFATAL, "invalid right-hand operand to WRT"); return NULL; } value = reloc_seg(f); if (value == NO_SEG) value = reloc_value(f) | SEG_ABS; else if (!(value & SEG_ABS) && !(value % 2) && critical) { nasm_error(ERR_NONFATAL, "invalid right-hand operand to WRT"); return NULL; } addtotemp(EXPR_WRT, value); g = finishtemp(); } e = add_vectors(e, g); } return e; }
static expr *expr6(int critical) { int32_t type; expr *e; int32_t label_seg; int64_t label_ofs; int64_t tmpval; bool rn_warn; char *scope; switch (i) { case '-': i = scan(scpriv, tokval); e = expr6(critical); if (!e) return NULL; return scalar_mult(e, -1L, false); case '+': i = scan(scpriv, tokval); return expr6(critical); case '~': i = scan(scpriv, tokval); e = expr6(critical); if (!e) return NULL; if (is_just_unknown(e)) return unknown_expr(); else if (!is_simple(e)) { nasm_error(ERR_NONFATAL, "`~' operator may only be applied to" " scalar values"); return NULL; } return scalarvect(~reloc_value(e)); case '!': i = scan(scpriv, tokval); e = expr6(critical); if (!e) return NULL; if (is_just_unknown(e)) return unknown_expr(); else if (!is_simple(e)) { nasm_error(ERR_NONFATAL, "`!' operator may only be applied to" " scalar values"); return NULL; } return scalarvect(!reloc_value(e)); case TOKEN_IFUNC: { enum ifunc func = tokval->t_integer; i = scan(scpriv, tokval); e = expr6(critical); if (!e) return NULL; if (is_just_unknown(e)) return unknown_expr(); else if (!is_simple(e)) { nasm_error(ERR_NONFATAL, "function may only be applied to" " scalar values"); return NULL; } return scalarvect(eval_ifunc(reloc_value(e), func)); } case TOKEN_SEG: i = scan(scpriv, tokval); e = expr6(critical); if (!e) return NULL; e = segment_part(e); if (!e) return NULL; if (is_unknown(e) && critical) { nasm_error(ERR_NONFATAL, "unable to determine segment base"); return NULL; } return e; case TOKEN_FLOATIZE: return eval_floatize(tokval->t_integer); case TOKEN_STRFUNC: return eval_strfunc(tokval->t_integer); case '(': i = scan(scpriv, tokval); e = bexpr(critical); if (!e) return NULL; if (i != ')') { nasm_error(ERR_NONFATAL, "expecting `)'"); return NULL; } i = scan(scpriv, tokval); return e; case TOKEN_NUM: case TOKEN_STR: case TOKEN_REG: case TOKEN_ID: case TOKEN_INSN: /* Opcodes that occur here are really labels */ case TOKEN_HERE: case TOKEN_BASE: case TOKEN_DECORATOR: begintemp(); switch (i) { case TOKEN_NUM: addtotemp(EXPR_SIMPLE, tokval->t_integer); break; case TOKEN_STR: tmpval = readstrnum(tokval->t_charptr, tokval->t_inttwo, &rn_warn); if (rn_warn) nasm_error(ERR_WARNING|ERR_PASS1, "character constant too long"); addtotemp(EXPR_SIMPLE, tmpval); break; case TOKEN_REG: addtotemp(tokval->t_integer, 1L); if (hint && hint->type == EAH_NOHINT) hint->base = tokval->t_integer, hint->type = EAH_MAKEBASE; break; case TOKEN_ID: case TOKEN_INSN: case TOKEN_HERE: case TOKEN_BASE: /* * If !location.known, this indicates that no * symbol, Here or Base references are valid because we * are in preprocess-only mode. */ if (!location.known) { nasm_error(ERR_NONFATAL, "%s not supported in preprocess-only mode", (i == TOKEN_HERE ? "`$'" : i == TOKEN_BASE ? "`$$'" : "symbol references")); addtotemp(EXPR_UNKNOWN, 1L); break; } type = EXPR_SIMPLE; /* might get overridden by UNKNOWN */ if (i == TOKEN_BASE) { label_seg = in_abs_seg ? abs_seg : location.segment; label_ofs = 0; } else if (i == TOKEN_HERE) { label_seg = in_abs_seg ? abs_seg : location.segment; label_ofs = in_abs_seg ? abs_offset : location.offset; } else { if (!lookup_label(tokval->t_charptr, &label_seg, &label_ofs)) { scope = local_scope(tokval->t_charptr); if (critical == 2) { nasm_error(ERR_NONFATAL, "symbol `%s%s' undefined", scope,tokval->t_charptr); return NULL; } else if (critical == 1) { nasm_error(ERR_NONFATAL, "symbol `%s%s' not defined before use", scope,tokval->t_charptr); return NULL; } else { if (opflags) *opflags |= OPFLAG_FORWARD; type = EXPR_UNKNOWN; label_seg = NO_SEG; label_ofs = 1; } } if (opflags && is_extern(tokval->t_charptr)) *opflags |= OPFLAG_EXTERN; } addtotemp(type, label_ofs); if (label_seg != NO_SEG) addtotemp(EXPR_SEGBASE + label_seg, 1L); break; case TOKEN_DECORATOR: addtotemp(EXPR_RDSAE, tokval->t_integer); break; } i = scan(scpriv, tokval); return finishtemp(); default: nasm_error(ERR_NONFATAL, "expression syntax error"); return NULL; } }