// BSAE3.bcpl - BCPL Compiler -- SAE Part 3 - Expression scanning // Copyright Xerox Corporation 1980 // Last modified on Sun 29 Oct 72 0245.41 by jec. // gmcd 18 sept 74 // last modified by Butterfield, May 9, 1979 1:15 PM // - EvalBinop, restore unsigned compares - 5/9 // - EvalBinop, comment out unsigned compares to bootstrap - 5/8 // - incorporate Paxton's unsigned compares - 5/8/79 // Lookat Attempt to evaluate a piece of tree at compile time. // *EvalBinop Evaluate a binary operator, at compile time. // *EvalUnop Evaluate a unary operator, at compile time. // EvalConst Evaluate a constant expression. // * local to this compilation. get "bsaex" // Lookat is applied to the address of a tree node (i.e., with Lookat(H2+x) ). // Let LVX be Lookat"s argument, and let x = rv LVX . There are three cases... // 1. The node can be evaluated at compile time. Then replace rv LVX by a NUMBER node // and return the address of a word containing the computed value // 2. The node can be simplified, as for a COND with constant condition or a table subscripted // by a constant. Then replace rv LVX by the simpler node and return Lookat(node) // 3. No simplification is possible. Lookat has been applied recursively to all sons of // the node that might be part of an expression. // Lookat also does the declarations for VALOF blocks // and looks up all names in the tree,replacing the name with // a pointer to its declaration node let Lookat(LVX) = valof [ let x = rv LVX // The usual sort of node. if x eq 0 resultis 0 // Nothing to do. let Value = nil // Put a computed value here if we get one. and Node = 0 // Put a new node here if we get one. and LValue = 0 // Put the addr of the value of a new node here // if we know its value if (x & NameBit) ne 0 do [ Node = CellWithName(x) if Node eq 0 do [ let xname = x & NameMask let p = UvecN while p le UvecP do [ if (Uvec!p & NameMask) eq xname break p = p + UvecN ] if p gr UvecP do [ SAEreport(10, xname) test p ls UvecT ifnot p = 0 ifso [ Uvec!p = xname + LABEL; Uvec!(p+1) = 0; UvecP = p ] ] Uvec!(p+1) = Uvec!(p+1) + 1 Node = lv Uvec!p ] rv LVX = Node + NameBit LValue = Node!0 & TypeMask if LValue eq LOCAL do [ if DvecLoc ls DvecP do [ SAEreport(8, x & NameMask) resultis 0 ] ] if LValue eq EXTLABEL % LValue eq ZEXTLABEL do [ if Node!1 eq 0 do [ Node!1 = Nextstatic() OutputStatic(Node) resultis 0 ] ] test LValue eq CONSTANT ifso resultis lv Node!1 ifnot resultis 0 ] let Op = H1!x switchon Op into [ case NUMBER: case CHARCONST: case TRUE: case FALSE: case NIL: resultis H2+x // It is a simple constant case PLUS: case MINUS: case MULT: case EQ: case NE: case GR: case LS: case GE: case LE: case UGR: case ULS: case UGE: case ULE: case LSHIFT: case RSHIFT: case LOGAND: case LOGOR: case EQV: case NEQV: case DIV: case REM: [ let L, R = Lookat(H2+x), Lookat(H3+x) // Look at the two sons. unless L > 0 % R > 0 resultis 0 // Return if neither was evaluated. if L > 0 & R > 0 do // Both were evaluated. [ Value = EvalBinop(Op, rv L, rv R) // Compute the value. endcase ] let LC, RC = L > 0, R > 0 // Switches for L and R being constant. and LX, RX = nil, nil // For the values. and L0, L1, LT, LF, R0, R1, RT, RF = false,false,false,false,false,false,false,false if LC do // Left operand has been evaluated. [ LX = rv L // Value of the operand. if LX eq 0 do L0 = true // L0 is true if LX is +0 or -0 if LX eq 1 do L1 = true // LX is 1 if LX eq true do LT = true // LX is true if LX eq false do LF = true // LX is false ] if RC do // Right operand has been evaluated. [ RX = rv R // The value of the operand. if RX eq 0 do R0 = true // R0 is true if RX is +0 or -0 if RX eq 1 do R1 = true if RX eq true do RT = true if RX eq false do RF = true ] switchon Op into [ case PLUS: if L0 do [ Node = H3!x; endcase ] // 0+x ? x if R0 do [ Node = H2!x; endcase ] // x+0 ? x resultis 0 case MINUS: if L0 do [ Node = x; H1!Node = NEG H2!Node = H3!x; endcase ] // 0-x ? neg x if R0 do [ Node = H2!x; endcase ] // x-0 ? x resultis 0 case MULT: if L0 % R0 do [ Value = 0; endcase ] // 0*x ? 0,. x*0 ? 0 if L1 do [ Node = H3!x; endcase ] // 1*x ? x if R1 do [ Node = H2!x; endcase ] // x*1 ? x resultis 0 case DIV: if L0 do [ Value = 0; endcase ] // 0/x ? 0 if R1 do [ Node = H2!x; endcase ] // x/1 ? x // If SCALE ocode ever exists, check for RX = 2n and replace by shift. resultis 0 case LOGAND: if LF % RF do [ Value = false; endcase ] // false&x ? false,. x&false ? false if LT do [ Node = H3!x; endcase ] // true&x ? x if RT do [ Node = H2!x; endcase ] // x&true ? x resultis 0 case LOGOR: if LT % RT do [ Value = true; endcase ] // true%x ? true x%true ? true if LF do [ Node = H3!x; endcase ] // false%x ? x if RF do [ Node = H2!x; endcase ] // x%false ? x resultis 0 case LSHIFT: case RSHIFT: if R0 do [ Node = H2!x; endcase ] // Don"t shift by zero. resultis 0 case EQV: if LF do [ Node = x; H1!Node = NOT H2!Node = H3!x; endcase ] // false eqv x ? not x if RF do [ Node = x; H1!Node = NOT H2!Node = H2!x; endcase ] // x eqv false ? not x if LT do [ Node = H3!x; endcase ] // true eqv x ? x if RT do [ Node = H2!x; endcase ] // x eqv true ? x resultis 0 case NEQV: if LF do [ Node = H3!x; endcase ] // false neqv x ? x if RF do [ Node = H2!x; endcase ] // x neqv false ? x if LT do [ Node = x; H1!Node = NOT H2!Node = H3!x; endcase ] // true neqv x ? not x if RT do [ Node = x; H1!Node = NOT H2!Node = H2!x; endcase ] // x neqv true ? not x resultis 0 default: resultis 0 ] endcase // Take all above "endcase"s to the end of this function. ] case NEG: case NOT: [ let L = Lookat(H2+x) // Examine the son. unless L > 0 resultis 0 // Done if not evaluated. Value = EvalUnop(Op, rv L) endcase ] case COND: [ let B = Lookat(H2+x) // Examine the conditional arm. unless B > 0 do [ Lookat(H3+x); Lookat(H4+x); resultis 0 ] Node = (rv B ? H3, H4)!x // The selected arm. LValue = Lookat(lv Node) endcase ] case VECAP: [ let A, B, LA, LB = nil,nil,nil,nil LA = Lookat(H2+x); LB = Lookat(H3+x) A = H2!x; B = H3!x if LA > 0 do [ let t, Lt = A, LA; A = B; LA = LB; B, LB = t, Lt ] resultis 0 ] case LV: [ let y = H2!x unless (y & NameBit) ne 0 do [ if H1!y eq RV do [ Node=H2!y; LValue=Lookat(lv Node); endcase ] if H1!y eq VECAP do [ Node=y; H1!Node = PLUS; H2!Node = H2!y; H3!Node = H3!y LValue=Lookat(lv Node); endcase ] ] Lookat(H2+x) resultis 0 ] case RV: Lookat(H2+x) resultis 0 case VALOF: [ let DE, DS = DvecE, DvecS Decllabels(H2!x) Declvars(H2!x) DvecE, DvecS = DE, DS resultis 0 ] case TABLE: [ let n = H2!x for i = 1 to n do (H2+i)!x = EvalConst(H2+i+x) resultis 0 ] case SIZE: [ let L = LookatQual(H3+x) resultis lv H2!L ] case OFFSET: [ let L = LookatQual(H3+x) unless H3!L eq 0 resultis 0 resultis lv H1!L ] case LEFTLUMP: case RIGHTLUMP: [ let LA = Lookat(H2+x) let L = LookatQual(H4+x) resultis 0 ] case FNAP: case COMMA: Lookat(H2+x) Lookat(H3+x) resultis 0 case VEC: Lookat(H2+x) resultis 0 case STRINGCONST: resultis 0 default: SAEreport(-5) resultis 0 ] // Come here for all the above ""endcase""s. // We have either a new Node or a Value if Node ne 0 do [ rv LVX = Node // A new Node--replace the tree node with it resultis LValue // and return the addr of its value if we have it ] Node = x; H1!Node = NUMBER; H2!Node = Value // A Value rv LVX = Node // so replace the tree node with a NUMBER node resultis H2 + Node // and return the addr of its value ] and EvalBinop(Op, a, b) = valof switchon Op into [ case PLUS: resultis a + b case MINUS: resultis a - b case EQ: resultis a eq b case NE: resultis a ne b case LS: resultis a < b case GR: resultis a > b case LE: resultis a le b case GE: resultis a ge b case ULS: resultis a uls b case UGR: resultis a ugr b case ULE: resultis a ule b case UGE: resultis a uge b case MULT: resultis a * b case DIV: resultis a / b case REM: resultis a rem b case LSHIFT: resultis a lshift b case RSHIFT: resultis a rshift b case LOGAND: resultis a & b case LOGOR: resultis a % b case EQV: resultis a eqv b case NEQV: resultis a neqv b default: SAEreport(-6); resultis 0 ] and EvalUnop(Op, a) = valof switchon Op into [ case NEG: resultis - a case NOT: resultis not a default: SAEreport(-7); resultis 0 ] // This routine is used when the node MUST be evaluable at compile time. and EvalConst(LVX) = valof [ let x = rv LVX let lx = nil lx = Lookat(LVX) x = rv LVX if lx > 0 resultis rv lx SAEreport(9, -1) rv LVX = ZERONODE resultis 0 ]