/* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg * * Permission is granted to anyone to use this software for any purpose * on any computer system, and to redistribute it freely, with the * following restrictions: * 1) No charge may be made other than reasonable charges for reproduction. * 2) Modified versions must be clearly marked as such. * 3) The authors are not responsible for any harmful consequences * of using this software, even if they result from defects in it. * * expr.c * * Expression parse routines * * All routines return either NULL or a valid tree * binop nodes have non-null left and right * unop nodes have non-null left * * Special nodes: * '(' : function call. left:name-expr right:args * ',': if part of function arg list, ival:num. descendants * '?' : ?switch. left:test-expr right:':' part * ':' : left:true-expr right:false-expr * TCONV: left:convertee tptr:type-list * TSIZEOF: tptr:type-list * */ #include #include "param.h" #include "nodes.h" #include "tok.h" extern NODEP cur; NODEP getnode(); NODEP opt_follow(); extern int oflags[]; #define debug oflags['x'-'a'] advnode() { cur = getnode(); } fadvnode() { freenode(cur); cur = getnode(); } NODEP gete_or_ty() { NODEP getexpr(), makecast(); NODEP rv; if (is_ty_start()) { rv = makecast(); if (debug) { printf("TY_X"); printnode(rv); } return rv; } else return getexpr(); } /* call this for any expr including comma's */ NODEP getexpr() { NODEP np, get_f_expr(); np = get_f_expr(0); return np; } NODEP get_f_expr(flg) int flg; { NODEP assignx(); register NODEP op, lpart, rpart; int i = 0; lpart = assignx(); if (lpart == NULL) { return NULL; } i++; more: if (cur->e_token != ',') return lpart; op = cur; advnode(); rpart = assignx(); if (rpart == NULL) { error("',' expr syntax"); return lpart; } i++; op->n_left = lpart; op->n_right = rpart; op->e_type = E_BIN; op->e_ival = flg ? i : 0; lpart = op; if (debug) { printf("COMMA"); printnode(op); } goto more; } /* call this if you want expr w/o comma's */ NODEP assignx() { NODEP questx(); register NODEP op, lpart, rpart; lpart = questx(); if (lpart == NULL) return NULL; if (!isassign(cur->e_token) && cur->e_token != '=') return lpart; op = cur; advnode(); rpart = assignx(); if (rpart == NULL) { error("'=op' expr syntax"); return lpart; } op->n_left = lpart; op->n_right = rpart; op->e_type = E_BIN; if (debug) { printf("ASSIGN"); printnode(op); } return op; } /* call this if you want expr w/o assign's or comma's */ /* i.e. constant-expression */ NODEP questx() { NODEP binary(); register NODEP holdq, holdc; NODEP qpart, tpart, fpart; qpart = binary(); if (qpart == NULL) return NULL; if (cur->e_token != '?') return qpart; holdq = cur; advnode(); tpart = questx(); if (tpart == NULL || cur->e_token != ':') { bad: error("'?:' expr syntax"); return qpart; } holdc = cur; advnode(); fpart = questx(); if (fpart == NULL) goto bad; holdc->n_left = tpart; holdc->n_right = fpart; holdc->e_type = E_BIN; holdq->n_left = qpart; holdq->n_right = holdc; holdq->e_type = E_BIN; if (debug) { printf("QUEST"); printnode(holdq); } return holdq; } NODEP binary() { NODEP unary(), buildbin(); register NODEP rv, op, e2; rv = unary(); if (rv == NULL) return NULL; rv->e_prec = 0; more: if (cur->e_prec == 0) /* not binary op */ return rv; op = cur; advnode(); e2 = unary(); if (e2 == NULL) { error("bin-op expr syntax"); return rv; } e2->e_prec = 0; rv = buildbin(rv, op, e2); if (debug) { printf("BINARY"); printnode(rv); } goto more; } NODEP buildbin(lpart, op, upart) NODEP lpart, op, upart; { register NODEP look, tail; NODEP rv; tail = NULL; look = lpart; for (look=lpart; op->e_prec < look->e_prec; look=look->n_right) tail = look; if (tail == NULL) { op->n_left = lpart; op->n_right = upart; rv = op; } else { tail->n_right = op; op->n_left = look; op->n_right = upart; rv = lpart; } op->e_type = E_BIN; return rv; } NODEP unary() { register NODEP tp,e1; NODEP primary(); if (cur->e_flags & CAN_U) { tp = cur; advnode(); if (tp->e_prec) { /* also have BINARY op */ tp->e_token = UNARY tp->e_token; strcat(tp->n_name, "U"); } tp->n_left = unary(); tp->e_type = E_UNARY; goto check; } else switch (cur->e_token) { case '(': fadvnode(); tp = gete_or_ty(); if (cur->e_token != ')') { error("missing )"); } else fadvnode(); if (tp == NULL) return NULL; if (tp->e_token == TCONV && tp->n_left == NULL) { sprintf(tp->n_name, "cast to"); tp->n_left = unary(); tp->e_type = E_UNARY; } else { tp = opt_follow(tp); goto out; } goto check; case K_SIZEOF: tp = cur; advnode(); if (cur->e_token == '(') { /* may be type expr */ fadvnode(); e1 = gete_or_ty(); if (cur->e_token != ')') { error("missing )"); } else fadvnode(); } else e1 = unary(); if (e1 == NULL) { error("sizeof expr syntax"); return NULL; } if (e1->e_token == TCONV) { freeunit(tp); e1->e_token = TSIZEOF; sprintf(e1->n_name, "T-sizeof"); tp = e1; tp->e_type = E_LEAF; goto out; } else { tp->e_type = E_UNARY; tp->n_left = e1; } goto check; default: tp = primary(); goto out; } check: if (tp == NULL) return NULL; if (tp->n_left == NULL) { error("u-op expr syntax"); return NULL; } out: if (debug) { printf("UNARY"); printnode(tp); } return tp; } NODEP primary() { register NODEP e1; switch (cur->e_token) { case ID: case ICON: case FCON: case SCON: e1 = cur; e1->e_type = E_LEAF; advnode(); break; case '(': fadvnode(); e1 = getexpr(); if (cur->e_token != ')') error("missing )"); else fadvnode(); break; default: e1 = NULL; } if (e1 == NULL) return NULL; return opt_follow(e1); } NODEP opt_follow(np) NODEP np; { register NODEP tp, e1, t2; switch (cur->e_token) { case '[': tp = cur; advnode(); e1 = getexpr(); if (cur->e_token != ']') { error("missing ]"); return np; } else { t2 = cur; advnode(); } if (e1 == NULL) { error("empty []"); return np; } t2->n_left = np; t2->n_right = e1; t2->e_type = E_BIN; t2->e_token = '+'; strcpy(t2->n_name, "+ ["); tp->n_left = t2; tp->e_type = E_UNARY; tp->e_token = STAR; strcpy(tp->n_name, "U*"); goto out; case '(': tp = cur; advnode(); e1 = get_f_expr(1); if (cur->e_token != ')') error("expect )"); else fadvnode(); tp->n_left = np; tp->n_right = e1; tp->e_type = E_SPEC; goto out; case '.': case ARROW: tp = cur; advnode(); if (cur->e_token != ID) { error("expect ID"); return np; } tp->n_left = np; tp->n_right = cur; tp->e_type = E_SPEC; if (tp->e_token == ARROW) { /* make into (*X).Y */ tp->e_token = '.'; strcpy(tp->n_name, "."); t2 = allocnode(); t2->e_token = STAR; t2->n_left = np; t2->e_type = E_UNARY; strcpy(t2->n_name, "U*"); tp->n_left = t2; } advnode(); goto out; case DOUBLE '+': case DOUBLE '-': tp = cur; advnode(); tp->e_token = (tp->e_token == DOUBLE '+') ? POSTINC : POSTDEC; strcat(tp->n_name, "post"); tp->n_left = np; tp->e_type = E_UNARY; goto out; default: return np; } out: return opt_follow(tp); } /* restricted version of unary for declarations or coertions */ /* allows NULL primary part */ NODEP declarator() { register NODEP tp,e1; NODEP ty_primary(), ty_follow(); if (cur->e_token == '*') { tp = cur; tp->e_token = UNARY tp->e_token; strcat(tp->n_name, "U"); advnode(); tp->n_left = declarator(); return tp; } else switch (cur->e_token) { case '(': tp = cur; advnode(); e1 = declarator(); if (cur->e_token != ')') { error("expect )"); } else fadvnode(); if (e1 == NULL) { /* special "fun of" */ /* left and right already NULL */ return ty_follow(tp); } else { freeunit(tp); return ty_follow(e1); } default: return ty_primary(); } } /* restricted version of primary for "declarator" */ NODEP ty_primary() { register NODEP e1; NODEP ty_follow(); switch (cur->e_token) { case ID: e1 = cur; advnode(); break; case '(': fadvnode(); e1 = declarator(); if (cur->e_token != ')') error("expect )"); else fadvnode(); break; default: e1 = NULL; } return ty_follow(e1); } /* restricted version of opt_follow for 'declarator' */ /* allow null [] */ NODEP ty_follow(np) NODEP np; { register NODEP tp, e1; NODEP ty_args(); switch (cur->e_token) { case '[': tp = cur; advnode(); e1 = questx(); if (cur->e_token != ']') error("expect ]"); else fadvnode(); tp->n_left = np; tp->n_right = e1; goto out; case '(': tp = cur; advnode(); e1 = ty_args(); /* allow args of fun to follow */ if (cur->e_token != ')') error("expect )"); else fadvnode(); tp->n_left = np; tp->n_right = e1; goto out; default: return np; } out: return ty_follow(tp); } /* called for args of function declaration or NULL */ NODEP ty_args() { NODEP opt_id(); register NODEP rv, tail, new; rv = opt_id(); if (rv == NULL) return NULL; tail = rv; more: if (cur->e_token != ',') return rv; fadvnode(); new = opt_id(); if (new == NULL) { error("expect as-op value"); return rv; } tail->n_left = new; tail = new; goto more; } NODEP opt_id() { NODEP rv; if (cur->e_token == ID) { rv = cur; advnode(); return rv; } else return NULL; }