1 /* 2 * Copyright (c) 1983 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 static char sccsid[] = "@(#)check.c 5.3 (Berkeley) 05/23/89"; 20 #endif /* not lint */ 21 22 /* 23 * Check a tree for semantic correctness. 24 */ 25 26 #include "defs.h" 27 #include "tree.h" 28 #include "operators.h" 29 #include "events.h" 30 #include "symbols.h" 31 #include "scanner.h" 32 #include "source.h" 33 #include "object.h" 34 #include "mappings.h" 35 #include "process.h" 36 #include <signal.h> 37 38 #ifndef public 39 #endif 40 41 /* 42 * Check that the nodes in a tree have the correct arguments 43 * in order to be evaluated. Basically the error checking here 44 * frees the evaluation routines from worrying about anything 45 * except dynamic errors, e.g. subscript out of range. 46 */ 47 48 public check(p) 49 register Node p; 50 { 51 Node p1, p2; 52 Address addr; 53 Symbol f; 54 55 checkref(p); 56 switch (p->op) { 57 case O_ASSIGN: 58 p1 = p->value.arg[0]; 59 p2 = p->value.arg[1]; 60 if (varIsSet("$unsafeassign")) { 61 if (size(p1->nodetype) != size(p2->nodetype)) { 62 error("incompatible sizes"); 63 } 64 } else if (not compatible(p1->nodetype, p2->nodetype)) { 65 error("incompatible types"); 66 } 67 break; 68 69 case O_CATCH: 70 case O_IGNORE: 71 if (p->value.lcon < 0 or p->value.lcon > NSIG) { 72 error("invalid signal number"); 73 } 74 break; 75 76 case O_CONT: 77 if (p->value.lcon != DEFSIG and ( 78 p->value.lcon < 0 or p->value.lcon > NSIG) 79 ) { 80 error("invalid signal number"); 81 } 82 break; 83 84 case O_DUMP: 85 if (p->value.arg[0] != nil) { 86 if (p->value.arg[0]->op == O_SYM) { 87 f = p->value.arg[0]->value.sym; 88 if (not isblock(f)) { 89 error("\"%s\" is not a block", symname(f)); 90 } 91 } else { 92 beginerrmsg(); 93 fprintf(stderr, "expected a symbol, found \""); 94 prtree(stderr, p->value.arg[0]); 95 fprintf(stderr, "\""); 96 enderrmsg(); 97 } 98 } 99 break; 100 101 case O_LIST: 102 if (p->value.arg[0]->op == O_SYM) { 103 f = p->value.arg[0]->value.sym; 104 if (not isblock(f) or ismodule(f)) { 105 error("\"%s\" is not a procedure or function", symname(f)); 106 } 107 addr = firstline(f); 108 if (addr == NOADDR) { 109 error("\"%s\" is empty", symname(f)); 110 } 111 } 112 break; 113 114 case O_TRACE: 115 case O_TRACEI: 116 chktrace(p); 117 break; 118 119 case O_STOP: 120 case O_STOPI: 121 chkstop(p); 122 break; 123 124 case O_CALLPROC: 125 case O_CALL: 126 if (not isroutine(p->value.arg[0]->nodetype)) { 127 beginerrmsg(); 128 fprintf(stderr, "\""); 129 prtree(stderr, p->value.arg[0]); 130 fprintf(stderr, "\" not call-able"); 131 enderrmsg(); 132 } 133 break; 134 135 case O_WHEREIS: 136 if (p->value.arg[0]->op == O_SYM and 137 p->value.arg[0]->value.sym == nil) { 138 error("symbol not defined"); 139 } 140 break; 141 142 default: 143 break; 144 } 145 } 146 147 /* 148 * Check arguments to a trace command. 149 */ 150 151 private chktrace(p) 152 Node p; 153 { 154 Node exp, place, cond; 155 156 exp = p->value.arg[0]; 157 place = p->value.arg[1]; 158 cond = p->value.arg[2]; 159 if (exp == nil) { 160 chkblock(place); 161 } else if (exp->op == O_LCON or exp->op == O_QLINE) { 162 if (place != nil) { 163 error("unexpected \"at\" or \"in\""); 164 } 165 if (p->op == O_TRACE) { 166 chkline(exp); 167 } else { 168 chkaddr(exp); 169 } 170 } else if (place != nil and (place->op == O_QLINE or place->op == O_LCON)) { 171 if (p->op == O_TRACE) { 172 chkline(place); 173 } else { 174 chkaddr(place); 175 } 176 } else { 177 if (exp->op != O_RVAL and exp->op != O_SYM and exp->op != O_CALL) { 178 error("can't trace expressions"); 179 } 180 chkblock(place); 181 } 182 } 183 184 /* 185 * Check arguments to a stop command. 186 */ 187 188 private chkstop(p) 189 Node p; 190 { 191 Node exp, place, cond; 192 193 exp = p->value.arg[0]; 194 place = p->value.arg[1]; 195 cond = p->value.arg[2]; 196 if (exp != nil) { 197 if (exp->op != O_RVAL and exp->op != O_SYM and exp->op != O_LCON) { 198 beginerrmsg(); 199 fprintf(stderr, "expected variable, found "); 200 prtree(stderr, exp); 201 enderrmsg(); 202 } 203 chkblock(place); 204 } else if (place != nil) { 205 if (place->op == O_SYM) { 206 chkblock(place); 207 } else { 208 if (p->op == O_STOP) { 209 chkline(place); 210 } else { 211 chkaddr(place); 212 } 213 } 214 } 215 } 216 217 /* 218 * Check to see that the given node specifies some subprogram. 219 * Nil is ok since that means the entire program. 220 */ 221 222 private chkblock(b) 223 Node b; 224 { 225 Symbol p, outer; 226 227 if (b != nil) { 228 if (b->op != O_SYM) { 229 beginerrmsg(); 230 fprintf(stderr, "expected subprogram, found "); 231 prtree(stderr, b); 232 enderrmsg(); 233 } else if (ismodule(b->value.sym)) { 234 outer = b->value.sym; 235 while (outer != nil) { 236 find(p, outer->name) where p->block == outer endfind(p); 237 if (p == nil) { 238 outer = nil; 239 error("\"%s\" is not a subprogram", symname(b->value.sym)); 240 } else if (ismodule(p)) { 241 outer = p; 242 } else { 243 outer = nil; 244 b->value.sym = p; 245 } 246 } 247 } else if ( 248 b->value.sym->class == VAR and 249 b->value.sym->name == b->value.sym->block->name and 250 b->value.sym->block->class == FUNC 251 ) { 252 b->value.sym = b->value.sym->block; 253 } else if (not isblock(b->value.sym)) { 254 error("\"%s\" is not a subprogram", symname(b->value.sym)); 255 } 256 } 257 } 258 259 /* 260 * Check to make sure a node corresponds to a source line. 261 */ 262 263 private chkline(p) 264 Node p; 265 { 266 if (p == nil) { 267 error("missing line"); 268 } else if (p->op != O_QLINE and p->op != O_LCON) { 269 error("expected source line number, found \"%t\"", p); 270 } 271 } 272 273 /* 274 * Check to make sure a node corresponds to an address. 275 */ 276 277 private chkaddr(p) 278 Node p; 279 { 280 if (p == nil) { 281 error("missing address"); 282 } else if (p->op != O_LCON and p->op != O_QLINE) { 283 beginerrmsg(); 284 fprintf(stderr, "expected address, found \""); 285 prtree(stderr, p); 286 fprintf(stderr, "\""); 287 enderrmsg(); 288 } 289 } 290