Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
lcc/src/expr.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
executable file
711 lines (683 sloc)
18 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "c.h" | |
| static char rcsid[] = "$Id$"; | |
| static char prec[] = { | |
| #define xx(a,b,c,d,e,f,g) c, | |
| #define yy(a,b,c,d,e,f,g) c, | |
| #include "token.h" | |
| }; | |
| static int oper[] = { | |
| #define xx(a,b,c,d,e,f,g) d, | |
| #define yy(a,b,c,d,e,f,g) d, | |
| #include "token.h" | |
| }; | |
| float refinc = 1.0; | |
| static Tree expr2(void); | |
| static Tree expr3(int); | |
| static Tree nullcheck(Tree); | |
| static Tree postfix(Tree); | |
| static Tree unary(void); | |
| static Tree primary(void); | |
| static Type super(Type ty); | |
| static Type super(Type ty) { | |
| switch (ty->op) { | |
| case INT: | |
| if (ty->size < inttype->size) | |
| return inttype; | |
| break; | |
| case UNSIGNED: | |
| if (ty->size < unsignedtype->size) | |
| return unsignedtype; | |
| break; | |
| case POINTER: | |
| return unsignedptr; | |
| } | |
| return ty; | |
| } | |
| Tree expr(int tok) { | |
| static char stop[] = { IF, ID, '}', 0 }; | |
| Tree p = expr1(0); | |
| while (t == ',') { | |
| Tree q; | |
| t = gettok(); | |
| q = pointer(expr1(0)); | |
| p = tree(RIGHT, q->type, root(value(p)), q); | |
| } | |
| if (tok) | |
| test(tok, stop); | |
| return p; | |
| } | |
| Tree expr0(int tok) { | |
| return root(expr(tok)); | |
| } | |
| Tree expr1(int tok) { | |
| static char stop[] = { IF, ID, 0 }; | |
| Tree p = expr2(); | |
| if (t == '=' | |
| || (prec[t] >= 6 && prec[t] <= 8) | |
| || (prec[t] >= 11 && prec[t] <= 13)) { | |
| int op = t; | |
| t = gettok(); | |
| if (oper[op] == ASGN) | |
| p = asgntree(ASGN, p, value(expr1(0))); | |
| else | |
| { | |
| expect('='); | |
| p = incr(op, p, expr1(0)); | |
| } | |
| } | |
| if (tok) | |
| test(tok, stop); | |
| return p; | |
| } | |
| Tree incr(int op, Tree v, Tree e) { | |
| return asgntree(ASGN, v, (*optree[op])(oper[op], v, e)); | |
| } | |
| static Tree expr2(void) { | |
| Tree p = expr3(4); | |
| if (t == '?') { | |
| Tree l, r; | |
| Coordinate pts[2]; | |
| if (Aflag > 1 && isfunc(p->type)) | |
| warning("%s used in a conditional expression\n", | |
| funcname(p)); | |
| p = pointer(p); | |
| t = gettok(); | |
| pts[0] = src; | |
| l = pointer(expr(':')); | |
| pts[1] = src; | |
| r = pointer(expr2()); | |
| if (generic(p->op) != CNST && events.points) | |
| { | |
| apply(events.points, &pts[0], &l); | |
| apply(events.points, &pts[1], &r); | |
| } | |
| p = condtree(p, l, r); | |
| } | |
| return p; | |
| } | |
| Tree value(Tree p) { | |
| int op = generic(rightkid(p)->op); | |
| if (p->type != voidtype | |
| && (op==AND || op==OR || op==NOT || op==EQ || op==NE | |
| || op== LE || op==LT || op== GE || op==GT)) | |
| p = condtree(p, consttree(1, inttype), | |
| consttree(0, inttype)); | |
| return p; | |
| } | |
| static Tree expr3(int k) { | |
| int k1; | |
| Tree p = unary(); | |
| for (k1 = prec[t]; k1 >= k; k1--) | |
| while (prec[t] == k1 && *cp != '=') { | |
| Tree r; | |
| Coordinate pt; | |
| int op = t; | |
| t = gettok(); | |
| pt = src; | |
| p = pointer(p); | |
| if (op == ANDAND || op == OROR) { | |
| r = pointer(expr3(k1)); | |
| if (events.points) | |
| apply(events.points, &pt, &r); | |
| } else | |
| r = pointer(expr3(k1 + 1)); | |
| p = (*optree[op])(oper[op], p, r); | |
| } | |
| return p; | |
| } | |
| static Tree unary(void) { | |
| Tree p; | |
| switch (t) { | |
| case '*': t = gettok(); p = unary(); p = pointer(p); | |
| if (isptr(p->type) | |
| && (isfunc(p->type->type) || isarray(p->type->type))) | |
| p = retype(p, p->type->type); | |
| else { | |
| if (YYnull) | |
| p = nullcheck(p); | |
| p = rvalue(p); | |
| } break; | |
| case '&': t = gettok(); p = unary(); if (isarray(p->type) || isfunc(p->type)) | |
| p = retype(p, ptr(p->type)); | |
| else | |
| p = lvalue(p); | |
| if (isaddrop(p->op) && p->u.sym->sclass == REGISTER) | |
| error("invalid operand of unary &; `%s' is declared register\n", p->u.sym->name); | |
| else if (isaddrop(p->op)) | |
| p->u.sym->addressed = 1; | |
| break; | |
| case '+': t = gettok(); p = unary(); p = pointer(p); | |
| if (isarith(p->type)) | |
| p = cast(p, promote(p->type)); | |
| else | |
| typeerror(ADD, p, NULL); break; | |
| case '-': t = gettok(); p = unary(); p = pointer(p); | |
| if (isarith(p->type)) { | |
| Type ty = promote(p->type); | |
| p = cast(p, ty); | |
| if (isunsigned(ty)) { | |
| warning("unsigned operand of unary -\n"); | |
| p = simplify(ADD, ty, simplify(BCOM, ty, p, NULL), cnsttree(ty, 1UL)); | |
| } else | |
| p = simplify(NEG, ty, p, NULL); | |
| } else | |
| typeerror(SUB, p, NULL); break; | |
| case '~': t = gettok(); p = unary(); p = pointer(p); | |
| if (isint(p->type)) { | |
| Type ty = promote(p->type); | |
| p = simplify(BCOM, ty, cast(p, ty), NULL); | |
| } else | |
| typeerror(BCOM, p, NULL); break; | |
| case '!': t = gettok(); p = unary(); p = pointer(p); | |
| if (isscalar(p->type)) | |
| p = simplify(NOT, inttype, cond(p), NULL); | |
| else | |
| typeerror(NOT, p, NULL); break; | |
| case INCR: t = gettok(); p = unary(); p = incr(INCR, pointer(p), consttree(1, inttype)); break; | |
| case DECR: t = gettok(); p = unary(); p = incr(DECR, pointer(p), consttree(1, inttype)); break; | |
| case TYPECODE: case SIZEOF: { int op = t; | |
| Type ty; | |
| p = NULL; | |
| t = gettok(); | |
| if (t == '(') { | |
| t = gettok(); | |
| if (istypename(t, tsym)) { | |
| ty = typename(); | |
| expect(')'); | |
| } else { | |
| p = postfix(expr(')')); | |
| ty = p->type; | |
| } | |
| } else { | |
| p = unary(); | |
| ty = p->type; | |
| } | |
| assert(ty); | |
| if (op == TYPECODE) | |
| p = cnsttree(inttype, (long)ty->op); | |
| else { | |
| if (isfunc(ty) || ty->size == 0) | |
| error("invalid type argument `%t' to `sizeof'\n", ty); | |
| else if (p && rightkid(p)->op == FIELD) | |
| error("`sizeof' applied to a bit field\n"); | |
| p = cnsttree(unsignedlong, (unsigned long)ty->size); | |
| } } break; | |
| case '(': | |
| t = gettok(); | |
| if (istypename(t, tsym)) { | |
| Type ty, ty1 = typename(), pty; | |
| expect(')'); | |
| ty = unqual(ty1); | |
| if (isenum(ty)) { | |
| Type ty2 = ty->type; | |
| if (isconst(ty1)) | |
| ty2 = qual(CONST, ty2); | |
| if (isvolatile(ty1)) | |
| ty2 = qual(VOLATILE, ty2); | |
| ty1 = ty2; | |
| ty = ty->type; | |
| } | |
| p = pointer(unary()); | |
| pty = p->type; | |
| if (isenum(pty)) | |
| pty = pty->type; | |
| if (isarith(pty) && isarith(ty) | |
| || isptr(pty) && isptr(ty)) { | |
| explicitCast++; | |
| p = cast(p, ty); | |
| explicitCast--; | |
| } else if (isptr(pty) && isint(ty) | |
| || isint(pty) && isptr(ty)) { | |
| if (Aflag >= 1 && ty->size < pty->size) | |
| warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, ty); | |
| p = cast(p, ty); | |
| } else if (ty != voidtype) { | |
| error("cast from `%t' to `%t' is illegal\n", | |
| p->type, ty1); | |
| ty1 = inttype; | |
| } | |
| if (generic(p->op) == INDIR || ty->size == 0) | |
| p = tree(RIGHT, ty1, NULL, p); | |
| else | |
| p = retype(p, ty1); | |
| } else | |
| p = postfix(expr(')')); | |
| break; | |
| default: | |
| p = postfix(primary()); | |
| } | |
| return p; | |
| } | |
| static Tree postfix(Tree p) { | |
| for (;;) | |
| switch (t) { | |
| case INCR: p = tree(RIGHT, p->type, | |
| tree(RIGHT, p->type, | |
| p, | |
| incr(t, p, consttree(1, inttype))), | |
| p); | |
| t = gettok(); break; | |
| case DECR: p = tree(RIGHT, p->type, | |
| tree(RIGHT, p->type, | |
| p, | |
| incr(t, p, consttree(1, inttype))), | |
| p); | |
| t = gettok(); break; | |
| case '[': { | |
| Tree q; | |
| t = gettok(); | |
| q = expr(']'); | |
| if (YYnull) | |
| if (isptr(p->type)) | |
| p = nullcheck(p); | |
| else if (isptr(q->type)) | |
| q = nullcheck(q); | |
| p = (*optree['+'])(ADD, pointer(p), pointer(q)); | |
| if (isptr(p->type) && isarray(p->type->type)) | |
| p = retype(p, p->type->type); | |
| else | |
| p = rvalue(p); | |
| } break; | |
| case '(': { | |
| Type ty; | |
| Coordinate pt; | |
| p = pointer(p); | |
| if (isptr(p->type) && isfunc(p->type->type)) | |
| ty = p->type->type; | |
| else { | |
| error("found `%t' expected a function\n", p->type); | |
| ty = func(voidtype, NULL, 1); | |
| p = retype(p, ptr(ty)); | |
| } | |
| pt = src; | |
| t = gettok(); | |
| p = call(p, ty, pt); | |
| } break; | |
| case '.': t = gettok(); | |
| if (t == ID) { | |
| if (isstruct(p->type)) { | |
| Tree q = addrof(p); | |
| p = field(q, token); | |
| q = rightkid(q); | |
| if (isaddrop(q->op) && q->u.sym->temporary) | |
| p = tree(RIGHT, p->type, p, NULL); | |
| } else | |
| error("left operand of . has incompatible type `%t'\n", | |
| p->type); | |
| t = gettok(); | |
| } else | |
| error("field name expected\n"); break; | |
| case DEREF: t = gettok(); | |
| p = pointer(p); | |
| if (t == ID) { | |
| if (isptr(p->type) && isstruct(p->type->type)) { | |
| if (YYnull) | |
| p = nullcheck(p); | |
| p = field(p, token); | |
| } else | |
| error("left operand of -> has incompatible type `%t'\n", p->type); | |
| t = gettok(); | |
| } else | |
| error("field name expected\n"); break; | |
| default: | |
| return p; | |
| } | |
| } | |
| static Tree primary(void) { | |
| Tree p; | |
| assert(t != '('); | |
| switch (t) { | |
| case ICON: | |
| case FCON: p = tree(mkop(CNST,tsym->type), tsym->type, NULL, NULL); | |
| p->u.v = tsym->u.c.v; | |
| break; | |
| case SCON: if (ischar(tsym->type->type)) | |
| tsym->u.c.v.p = stringn(tsym->u.c.v.p, tsym->type->size); | |
| else | |
| tsym->u.c.v.p = memcpy(allocate((tsym->type->size/widechar->size)*sizeof (int), PERM), | |
| tsym->u.c.v.p, (tsym->type->size/widechar->size)*sizeof (int)); | |
| tsym = constant(tsym->type, tsym->u.c.v); | |
| if (tsym->u.c.loc == NULL) | |
| tsym->u.c.loc = genident(STATIC, tsym->type, GLOBAL); | |
| p = idtree(tsym->u.c.loc); break; | |
| case ID: if (tsym == NULL) | |
| { | |
| Symbol p = install(token, &identifiers, level, PERM); | |
| p->src = src; | |
| if (getchr() == '(') { | |
| Symbol q = lookup(token, externals); | |
| p->type = func(inttype, NULL, 1); | |
| p->sclass = EXTERN; | |
| if (Aflag >= 1) | |
| warning("missing prototype\n"); | |
| if (q && !eqtype(q->type, p->type, 1)) | |
| warning("implicit declaration of `%s' does not match previous declaration at %w\n", q->name, &q->src); | |
| if (q == NULL) { | |
| q = install(p->name, &externals, GLOBAL, PERM); | |
| q->type = p->type; | |
| q->sclass = EXTERN; | |
| q->src = src; | |
| (*IR->defsymbol)(q); | |
| } | |
| p->u.alias = q; | |
| } else { | |
| error("undeclared identifier `%s'\n", p->name); | |
| p->sclass = AUTO; | |
| p->type = inttype; | |
| if (p->scope == GLOBAL) | |
| (*IR->defsymbol)(p); | |
| else | |
| addlocal(p); | |
| } | |
| t = gettok(); | |
| if (xref) | |
| use(p, src); | |
| return idtree(p); | |
| } | |
| if (xref) | |
| use(tsym, src); | |
| if (tsym->sclass == ENUM) | |
| p = consttree(tsym->u.value, inttype); | |
| else { | |
| if (tsym->sclass == TYPEDEF) | |
| error("illegal use of type name `%s'\n", tsym->name); | |
| p = idtree(tsym); | |
| } break; | |
| case FIRSTARG: | |
| if (level > PARAM && cfunc && cfunc->u.f.callee[0]) | |
| p = idtree(cfunc->u.f.callee[0]); | |
| else { | |
| error("illegal use of `%k'\n", FIRSTARG); | |
| p = cnsttree(inttype, 0L); | |
| } | |
| break; | |
| default: | |
| error("illegal expression\n"); | |
| p = cnsttree(inttype, 0L); | |
| } | |
| t = gettok(); | |
| return p; | |
| } | |
| Tree idtree(Symbol p) { | |
| int op; | |
| Tree e; | |
| Type ty = p->type ? unqual(p->type) : voidptype; | |
| if (p->scope == GLOBAL || p->sclass == STATIC) | |
| op = ADDRG; | |
| else if (p->scope == PARAM) { | |
| op = ADDRF; | |
| if (isstruct(p->type) && !IR->wants_argb) | |
| { | |
| e = tree(mkop(op,voidptype), ptr(ptr(p->type)), NULL, NULL); | |
| e->u.sym = p; | |
| return rvalue(rvalue(e)); | |
| } | |
| } else if (p->sclass == EXTERN) { | |
| assert(p->u.alias); | |
| p = p->u.alias; | |
| op = ADDRG; | |
| } else | |
| op = ADDRL; | |
| p->ref += refinc; | |
| if (isarray(ty)) | |
| e = tree(mkop(op,voidptype), p->type, NULL, NULL); | |
| else if (isfunc(ty)) | |
| e = tree(mkop(op,funcptype), p->type, NULL, NULL); | |
| else | |
| e = tree(mkop(op,voidptype), ptr(p->type), NULL, NULL); | |
| e->u.sym = p; | |
| if (isptr(e->type)) | |
| e = rvalue(e); | |
| return e; | |
| } | |
| Tree rvalue(Tree p) { | |
| Type ty = deref(p->type); | |
| ty = unqual(ty); | |
| return tree(mkop(INDIR,ty), ty, p, NULL); | |
| } | |
| Tree lvalue(Tree p) { | |
| if (generic(p->op) != INDIR) { | |
| error("lvalue required\n"); | |
| return value(p); | |
| } else if (unqual(p->type) == voidtype) | |
| warning("`%t' used as an lvalue\n", p->type); | |
| return p->kids[0]; | |
| } | |
| Tree retype(Tree p, Type ty) { | |
| Tree q; | |
| if (p->type == ty) | |
| return p; | |
| q = tree(p->op, ty, p->kids[0], p->kids[1]); | |
| q->node = p->node; | |
| q->u = p->u; | |
| return q; | |
| } | |
| Tree rightkid(Tree p) { | |
| while (p && p->op == RIGHT) | |
| if (p->kids[1]) | |
| p = p->kids[1]; | |
| else if (p->kids[0]) | |
| p = p->kids[0]; | |
| else | |
| assert(0); | |
| assert(p); | |
| return p; | |
| } | |
| int hascall(Tree p) { | |
| if (p == 0) | |
| return 0; | |
| if (generic(p->op) == CALL || (IR->mulops_calls && | |
| (p->op == DIV+I || p->op == MOD+I || p->op == MUL+I | |
| || p->op == DIV+U || p->op == MOD+U || p->op == MUL+U))) | |
| return 1; | |
| return hascall(p->kids[0]) || hascall(p->kids[1]); | |
| } | |
| Type binary(Type xty, Type yty) { | |
| #define xx(t) if (xty == t || yty == t) return t | |
| xx(longdouble); | |
| xx(doubletype); | |
| xx(floattype); | |
| xx(unsignedlonglong); | |
| xx(longlong); | |
| xx(unsignedlong); | |
| if (xty == longtype && yty == unsignedtype | |
| || xty == unsignedtype && yty == longtype) | |
| if (longtype->size > unsignedtype->size) | |
| return longtype; | |
| else | |
| return unsignedlong; | |
| xx(longtype); | |
| xx(unsignedtype); | |
| return inttype; | |
| #undef xx | |
| } | |
| Tree pointer(Tree p) { | |
| if (isarray(p->type)) | |
| /* assert(p->op != RIGHT || p->u.sym == NULL), */ | |
| p = retype(p, atop(p->type)); | |
| else if (isfunc(p->type)) | |
| p = retype(p, ptr(p->type)); | |
| return p; | |
| } | |
| Tree cond(Tree p) { | |
| int op = generic(rightkid(p)->op); | |
| if (op == AND || op == OR || op == NOT | |
| || op == EQ || op == NE | |
| || op == LE || op == LT || op == GE || op == GT) | |
| return p; | |
| p = pointer(p); | |
| return (*optree[NEQ])(NE, p, consttree(0, inttype)); | |
| } | |
| Tree cast(Tree p, Type type) { | |
| Type src, dst; | |
| p = value(p); | |
| if (p->type == type) | |
| return p; | |
| dst = unqual(type); | |
| src = unqual(p->type); | |
| if (src->op != dst->op || src->size != dst->size) { | |
| switch (src->op) { | |
| case INT: | |
| if (src->size < inttype->size) | |
| p = simplify(CVI, inttype, p, NULL); | |
| break; | |
| case UNSIGNED: | |
| if (src->size < inttype->size) | |
| p = simplify(CVU, inttype, p, NULL); | |
| else if (src->size < unsignedtype->size) | |
| p = simplify(CVU, unsignedtype, p, NULL); | |
| break; | |
| case ENUM: | |
| p = retype(p, inttype); | |
| break; | |
| case POINTER: | |
| if (isint(dst) && src->size > dst->size) | |
| warning("conversion from `%t' to `%t' is undefined\n", p->type, type); | |
| p = simplify(CVP, super(src), p, NULL); | |
| break; | |
| case FLOAT: | |
| break; | |
| default: assert(0); | |
| } | |
| { | |
| src = unqual(p->type); | |
| dst = super(dst); | |
| if (src->op != dst->op) | |
| switch (src->op) { | |
| case INT: | |
| p = simplify(CVI, dst, p, NULL); | |
| break; | |
| case UNSIGNED: | |
| if (isfloat(dst)) { | |
| Type ssrc = signedint(src); | |
| Tree two = cnsttree(longdouble, (long double)2.0); | |
| p = (*optree['+'])(ADD, | |
| (*optree['*'])(MUL, | |
| two, | |
| simplify(CVU, ssrc, | |
| simplify(RSH, src, | |
| p, consttree(1, inttype)), NULL)), | |
| simplify(CVU, ssrc, | |
| simplify(BAND, src, | |
| p, consttree(1, unsignedtype)), NULL)); | |
| } else | |
| p = simplify(CVU, dst, p, NULL); | |
| break; | |
| case FLOAT: | |
| if (isunsigned(dst)) { | |
| Type sdst = signedint(dst); | |
| Tree c = cast(cnsttree(longdouble, (long double)sdst->u.sym->u.limits.max.i + 1), src); | |
| p = condtree( | |
| simplify(GE, src, p, c), | |
| (*optree['+'])(ADD, | |
| cast(cast(simplify(SUB, src, p, c), sdst), dst), | |
| cast(cnsttree(unsignedlong, (unsigned long)sdst->u.sym->u.limits.max.i + 1), dst)), | |
| simplify(CVF, sdst, p, NULL)); | |
| } else | |
| p = simplify(CVF, dst, p, NULL); | |
| break; | |
| default: assert(0); | |
| } | |
| dst = unqual(type); | |
| } | |
| } | |
| src = unqual(p->type); | |
| switch (src->op) { | |
| case INT: | |
| if (src->op != dst->op || src->size != dst->size) | |
| p = simplify(CVI, dst, p, NULL); | |
| break; | |
| case UNSIGNED: | |
| if (src->op != dst->op || src->size != dst->size) | |
| p = simplify(CVU, dst, p, NULL); | |
| break; | |
| case FLOAT: | |
| if (src->op != dst->op || src->size != dst->size) | |
| p = simplify(CVF, dst, p, NULL); | |
| break; | |
| case POINTER: | |
| if (src->op != dst->op) | |
| p = simplify(CVP, dst, p, NULL); | |
| else { | |
| if (isfunc(src->type) && !isfunc(dst->type) | |
| || !isfunc(src->type) && isfunc(dst->type)) | |
| warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, type); | |
| if (src->size != dst->size) | |
| p = simplify(CVP, dst, p, NULL); | |
| } | |
| break; | |
| default: assert(0); | |
| } | |
| return retype(p, type); | |
| } | |
| Tree field(Tree p, const char *name) { | |
| Field q; | |
| Type ty1, ty = p->type; | |
| if (isptr(ty)) | |
| ty = deref(ty); | |
| ty1 = ty; | |
| ty = unqual(ty); | |
| if ((q = fieldref(name, ty)) != NULL) { | |
| if (isarray(q->type)) { | |
| ty = q->type->type; | |
| if (isconst(ty1) && !isconst(ty)) | |
| ty = qual(CONST, ty); | |
| if (isvolatile(ty1) && !isvolatile(ty)) | |
| ty = qual(VOLATILE, ty); | |
| ty = array(ty, q->type->size/ty->size, q->type->align); | |
| } else { | |
| ty = q->type; | |
| if (isconst(ty1) && !isconst(ty)) | |
| ty = qual(CONST, ty); | |
| if (isvolatile(ty1) && !isvolatile(ty)) | |
| ty = qual(VOLATILE, ty); | |
| ty = ptr(ty); | |
| } | |
| if (YYcheck && !isaddrop(p->op) && q->offset > 0) /* omit */ | |
| p = nullcall(ty, YYcheck, p, consttree(q->offset, inttype)); /* omit */ | |
| else /* omit */ | |
| p = simplify(ADD+P, ty, p, consttree(q->offset, signedptr)); | |
| if (q->lsb) { | |
| p = tree(FIELD, ty->type, rvalue(p), NULL); | |
| p->u.field = q; | |
| } else if (!isarray(q->type)) | |
| p = rvalue(p); | |
| } else { | |
| error("unknown field `%s' of `%t'\n", name, ty); | |
| p = rvalue(retype(p, ptr(inttype))); | |
| } | |
| return p; | |
| } | |
| /* funcname - return name of function f or a function' */ | |
| char *funcname(Tree f) { | |
| if (isaddrop(f->op)) | |
| return stringf("`%s'", f->u.sym->name); | |
| return "a function"; | |
| } | |
| static Tree nullcheck(Tree p) { | |
| if (!needconst && YYnull && isptr(p->type)) { | |
| p = value(p); | |
| if (strcmp(YYnull->name, "_YYnull") == 0) { | |
| Symbol t1 = temporary(REGISTER, voidptype); | |
| p = tree(RIGHT, p->type, | |
| tree(OR, voidtype, | |
| cond(asgn(t1, cast(p, voidptype))), | |
| vcall(YYnull, voidtype, (file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL)), | |
| idtree(t1)); | |
| } | |
| else | |
| p = nullcall(p->type, YYnull, p, cnsttree(inttype, 0L)); | |
| } | |
| return p; | |
| } | |
| Tree nullcall(Type pty, Symbol f, Tree p, Tree e) { | |
| Type ty; | |
| if (isarray(pty)) | |
| return retype(nullcall(atop(pty), f, p, e), pty); | |
| ty = unqual(unqual(p->type)->type); | |
| return vcall(f, pty, | |
| p, e, | |
| cnsttree(inttype, (long)ty->size), | |
| cnsttree(inttype, (long)ty->align), | |
| (file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL); | |
| } |