static expr *expr3(int critical) { expr *e, *f; e = expr4(critical); if (!e) return NULL; while (i == TOKEN_SHL || i == TOKEN_SHR) { int j = i; i = scan(scpriv, tokval); f = expr4(critical); if (!f) return NULL; if (!(is_simple(e) || is_just_unknown(e)) || !(is_simple(f) || is_just_unknown(f))) { nasm_error(ERR_NONFATAL, "shift operator may only be applied to" " scalar values"); } else if (is_just_unknown(e) || is_just_unknown(f)) { e = unknown_expr(); } else switch (j) { case TOKEN_SHL: e = scalarvect(reloc_value(e) << reloc_value(f)); break; case TOKEN_SHR: e = scalarvect(((uint64_t)reloc_value(e)) >> reloc_value(f)); break; } } return e; }
static expr *expr2(int critical) { expr *e, *f; e = expr3(critical); if (!e) return NULL; while (i == '&') { i = scan(scpriv, tokval); f = expr3(critical); if (!f) return NULL; if (!(is_simple(e) || is_just_unknown(e)) || !(is_simple(f) || is_just_unknown(f))) { nasm_error(ERR_NONFATAL, "`&' operator may only be applied to" " scalar values"); } if (is_just_unknown(e) || is_just_unknown(f)) e = unknown_expr(); else e = scalarvect(reloc_value(e) & reloc_value(f)); } return e; }
static expr *rexp1(int critical) { expr *e, *f; e = rexp2(critical); if (!e) return NULL; while (i == TOKEN_DBL_XOR) { i = scan(scpriv, tokval); f = rexp2(critical); if (!f) return NULL; if (!(is_simple(e) || is_just_unknown(e)) || !(is_simple(f) || is_just_unknown(f))) { nasm_error(ERR_NONFATAL, "`^' operator may only be applied to" " scalar values"); } if (is_just_unknown(e) || is_just_unknown(f)) e = unknown_expr(); else e = scalarvect((int64_t)(!reloc_value(e) ^ !reloc_value(f))); } return e; }
/* * The SEG operator: calculate the segment part of a relocatable * value. Return NULL, as usual, if an error occurs. Report the * error too. */ static expr *segment_part(expr * e) { int32_t seg; if (is_unknown(e)) return unknown_expr(); if (!is_reloc(e)) { nasm_error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value"); return NULL; } seg = reloc_seg(e); if (seg == NO_SEG) { nasm_error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value"); return NULL; } else if (seg & SEG_ABS) { return scalarvect(seg & ~SEG_ABS); } else if (seg & 1) { nasm_error(ERR_NONFATAL, "SEG applied to something which" " is already a segment base"); return NULL; } else { int32_t base = ofmt->segbase(seg + 1); begintemp(); addtotemp((base == NO_SEG ? EXPR_UNKNOWN : EXPR_SEGBASE + base), 1L); return finishtemp(); } }
static struct ast_node* stmt(void *opaque) { struct ast_node *node; token_t prev_token; prev_token = current_token; if (match(TOKEN_FUNCTION)) node = process_function(opaque); else if (match(TOKEN_LOCAL)) node = process_local_declaration(opaque); else if (match(TOKEN_IF)) node = if_expr(opaque); else if (match(TOKEN_FOR)) node = for_expr(opaque); else if (match(TOKEN_WHILE)) node = while_expr(opaque); else if (match(TOKEN_BREAK)) node = break_expr(opaque); else if (match(TOKEN_CONTINUE)) node = continue_expr(opaque); else if (match(TOKEN_RETURN)) node = process_return_node(opaque); else if (match(TOKEN_LBRACE)) node = process_scope(opaque); else if (match(TOKEN_RBRACE)) node = end_scope_expr(opaque); else if (match(TOKEN_UNKNOWN)) node = unknown_expr(opaque); else node = other_expr(opaque); return node; }
static expr *rexp3(int critical) { expr *e, *f; int64_t v; e = expr0(critical); if (!e) return NULL; while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT || i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) { int j = i; i = scan(scpriv, tokval); f = expr0(critical); if (!f) return NULL; e = add_vectors(e, scalar_mult(f, -1L, false)); switch (j) { case TOKEN_EQ: case TOKEN_NE: if (is_unknown(e)) v = -1; /* means unknown */ else if (!is_really_simple(e) || reloc_value(e) != 0) v = (j == TOKEN_NE); /* unequal, so return true if NE */ else v = (j == TOKEN_EQ); /* equal, so return true if EQ */ break; default: if (is_unknown(e)) v = -1; /* means unknown */ else if (!is_really_simple(e)) { nasm_error(ERR_NONFATAL, "`%s': operands differ by a non-scalar", (j == TOKEN_LE ? "<=" : j == TOKEN_LT ? "<" : j == TOKEN_GE ? ">=" : ">")); v = 0; /* must set it to _something_ */ } else { int64_t vv = reloc_value(e); if (vv == 0) v = (j == TOKEN_LE || j == TOKEN_GE); else if (vv > 0) v = (j == TOKEN_GE || j == TOKEN_GT); else /* vv < 0 */ v = (j == TOKEN_LE || j == TOKEN_LT); } break; } if (v == -1) e = unknown_expr(); else e = scalarvect(v); } return e; }
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; } }
static expr *expr5(int critical) { expr *e, *f; e = expr6(critical); if (!e) return NULL; while (i == '*' || i == '/' || i == '%' || i == TOKEN_SDIV || i == TOKEN_SMOD) { int j = i; i = scan(scpriv, tokval); f = expr6(critical); if (!f) return NULL; if (j != '*' && (!(is_simple(e) || is_just_unknown(e)) || !(is_simple(f) || is_just_unknown(f)))) { nasm_error(ERR_NONFATAL, "division operator may only be applied to" " scalar values"); return NULL; } if (j != '*' && !is_unknown(f) && reloc_value(f) == 0) { nasm_error(ERR_NONFATAL, "division by zero"); return NULL; } switch (j) { case '*': if (is_simple(e)) e = scalar_mult(f, reloc_value(e), true); else if (is_simple(f)) e = scalar_mult(e, reloc_value(f), true); else if (is_just_unknown(e) && is_just_unknown(f)) e = unknown_expr(); else { nasm_error(ERR_NONFATAL, "unable to multiply two " "non-scalar objects"); return NULL; } break; case '/': if (is_just_unknown(e) || is_just_unknown(f)) e = unknown_expr(); else e = scalarvect(((uint64_t)reloc_value(e)) / ((uint64_t)reloc_value(f))); break; case '%': if (is_just_unknown(e) || is_just_unknown(f)) e = unknown_expr(); else e = scalarvect(((uint64_t)reloc_value(e)) % ((uint64_t)reloc_value(f))); break; case TOKEN_SDIV: if (is_just_unknown(e) || is_just_unknown(f)) e = unknown_expr(); else e = scalarvect(((int64_t)reloc_value(e)) / ((int64_t)reloc_value(f))); break; case TOKEN_SMOD: if (is_just_unknown(e) || is_just_unknown(f)) e = unknown_expr(); else e = scalarvect(((int64_t)reloc_value(e)) % ((int64_t)reloc_value(f))); break; } } return e; }