1*22559Sdist /* 2*22559Sdist * Copyright (c) 1980 Regents of the University of California. 3*22559Sdist * All rights reserved. The Berkeley software License Agreement 4*22559Sdist * specifies the terms and conditions for redistribution. 5*22559Sdist */ 65543Slinton 7*22559Sdist #ifndef lint 8*22559Sdist static char sccsid[] = "@(#)eval.c 5.1 (Berkeley) 06/06/85"; 9*22559Sdist #endif not lint 105543Slinton 115543Slinton /* 125562Slinton * Parse tree evaluation. 135543Slinton */ 145543Slinton 155543Slinton #include "defs.h" 165543Slinton #include "tree.h" 175543Slinton #include "sym.h" 185543Slinton #include "process.h" 195543Slinton #include "source.h" 205543Slinton #include "mappings.h" 215543Slinton #include "breakpoint.h" 225543Slinton #include "machine.h" 235543Slinton #include "tree.rep" 245543Slinton 256086Slinton #define Boolean char /* underlying representation type for booleans */ 266086Slinton 275543Slinton /* 285543Slinton * Evaluate a parse tree using a stack; value is left at top. 295543Slinton */ 305543Slinton 315562Slinton #define STACKSIZE 2000 325562Slinton 335562Slinton STACK stack[STACKSIZE]; 345543Slinton STACK *sp = &stack[0]; 355543Slinton 365543Slinton eval(p) 375543Slinton register NODE *p; 385543Slinton { 395782Slinton long r0, r1; 405782Slinton double fr0, fr1; 416874Slinton FILE *fp; 425543Slinton 435782Slinton if (p == NULL) { 445782Slinton return; 455782Slinton } 465782Slinton switch(degree(p->op)) { 475782Slinton case BINARY: 485782Slinton eval(p->right); 495782Slinton if (isreal(p->op)) { 505782Slinton fr1 = pop(double); 515782Slinton } else if (isint(p->op)) { 526076Slinton r1 = popsmall(p->right->nodetype); 535782Slinton } 545782Slinton /* fall through */ 555782Slinton case UNARY: 565782Slinton eval(p->left); 575782Slinton if (isreal(p->op)) { 585782Slinton fr0 = pop(double); 595782Slinton } else if (isint(p->op)) { 606076Slinton r0 = popsmall(p->left->nodetype); 615782Slinton } 625782Slinton break; 635782Slinton 645782Slinton default: 655782Slinton /* do nothing */; 665543Slinton } 675782Slinton switch(p->op) { 685782Slinton case O_NAME: { 695782Slinton SYM *s, *f; 705543Slinton 715782Slinton s = p->nameval; 725886Slinton if (!isvariable(s)) { 735886Slinton error("cannot evaluate a %s", classname(s)); 745886Slinton } else { 755886Slinton f = container(s); 765886Slinton if (!isactive(f)) { 775886Slinton error("\"%s\" is not active", name(f)); 785886Slinton } 796086Slinton push(long, address(s, NIL)); 805782Slinton } 815782Slinton break; 825782Slinton } 835543Slinton 845782Slinton case O_LCON: 855782Slinton switch (size(p->nodetype)) { 865782Slinton case sizeof(char): 875782Slinton push(char, p->lconval); 885782Slinton break; 895543Slinton 905782Slinton case sizeof(short): 915782Slinton push(short, p->lconval); 925782Slinton break; 935543Slinton 945782Slinton case sizeof(long): 955782Slinton push(long, p->lconval); 965782Slinton break; 975543Slinton 985782Slinton default: 995782Slinton panic("bad size %d for LCON", size(p->nodetype)); 1005782Slinton } 1015782Slinton break; 1025543Slinton 1035782Slinton case O_FCON: 1045782Slinton push(double, p->fconval); 1055782Slinton break; 1065543Slinton 1075782Slinton case O_SCON: { 1085782Slinton int len; 1095543Slinton 1105782Slinton len = size(p->nodetype); 1115782Slinton mov(p->sconval, sp, len); 1125782Slinton sp += len; 1135782Slinton break; 1145782Slinton } 1155543Slinton 1165782Slinton case O_INDEX: { 11711063Slinton long n; /* base address for array */ 11811063Slinton long i; /* index - lower bound */ 1195543Slinton 1206086Slinton n = pop(long); 12111063Slinton i = evalindex(p->left->nodetype, p->right); 1226086Slinton push(long, n + i*size(p->nodetype)); 1235782Slinton break; 1245782Slinton } 1255543Slinton 1265782Slinton case O_INDIR: { 1275782Slinton ADDRESS a; 1285543Slinton 1295782Slinton a = pop(ADDRESS); 1305782Slinton if (a == 0) { 1315782Slinton error("reference through nil pointer"); 1325782Slinton } 1335782Slinton dread(sp, a, sizeof(ADDRESS)); 1345782Slinton sp += sizeof(ADDRESS); 1355782Slinton break; 1365782Slinton } 1375543Slinton 1385782Slinton /* 1395782Slinton * Get the value of the expression addressed by the top of the stack. 1406076Slinton * Push the result back on the stack. 1415782Slinton */ 1425543Slinton 1435782Slinton case O_RVAL: { 1445782Slinton ADDRESS addr, len; 1455782Slinton long i; 1465543Slinton 1476086Slinton addr = pop(long); 1485782Slinton if (addr == 0) { 1495782Slinton error("reference through nil pointer"); 1505782Slinton } 1515782Slinton len = size(p->nodetype); 1525782Slinton if (!rpush(addr, len)) { 1535782Slinton error("expression too large to evaluate"); 1545782Slinton } 1555782Slinton break; 1565782Slinton } 1575543Slinton 1585782Slinton case O_COMMA: 1595782Slinton break; 1605543Slinton 1615782Slinton case O_ITOF: 1625782Slinton push(double, (double) r0); 1635782Slinton break; 1645543Slinton 1655782Slinton case O_ADD: 1665782Slinton push(long, r0+r1); 1675782Slinton break; 1685543Slinton 1695782Slinton case O_ADDF: 1705782Slinton push(double, fr0+fr1); 1715782Slinton break; 1725543Slinton 1735782Slinton case O_SUB: 1745782Slinton push(long, r0-r1); 1755782Slinton break; 1765543Slinton 1775782Slinton case O_SUBF: 1785782Slinton push(double, fr0-fr1); 1795782Slinton break; 1805543Slinton 1815782Slinton case O_NEG: 1825782Slinton push(long, -r0); 1835782Slinton break; 1845543Slinton 1855782Slinton case O_NEGF: 1865782Slinton push(double, -fr0); 1875782Slinton break; 1885543Slinton 1895782Slinton case O_MUL: 1905782Slinton push(long, r0*r1); 1915782Slinton break; 1925543Slinton 1935782Slinton case O_MULF: 1945782Slinton push(double, fr0*fr1); 1955782Slinton break; 1965543Slinton 1975782Slinton case O_DIVF: 1985782Slinton if (fr1 == 0) { 1995782Slinton error("error: division by 0"); 2005782Slinton } 2015782Slinton push(double, fr0/fr1); 2025782Slinton break; 2035543Slinton 2045782Slinton case O_DIV: 2055782Slinton if (r1 == 0) { 2065782Slinton error("error: div by 0"); 2075782Slinton } 2085782Slinton push(long, r0/r1); 2095782Slinton break; 2105543Slinton 2115782Slinton case O_MOD: 2125782Slinton if (r1 == 0) { 2135782Slinton error("error: mod by 0"); 2145782Slinton } 2155782Slinton push(long, r0%r1); 2165782Slinton break; 2175543Slinton 2185782Slinton case O_LT: 2196086Slinton push(Boolean, r0 < r1); 2205782Slinton break; 2215543Slinton 2225782Slinton case O_LTF: 2236086Slinton push(Boolean, fr0 < fr1); 2245782Slinton break; 2255543Slinton 2265782Slinton case O_LE: 2276086Slinton push(Boolean, r0 <= r1); 2285782Slinton break; 2295543Slinton 2305782Slinton case O_LEF: 2316086Slinton push(Boolean, fr0 <= fr1); 2325782Slinton break; 2335543Slinton 2345782Slinton case O_GT: 2356086Slinton push(Boolean, r0 > r1); 2365782Slinton break; 2375543Slinton 2385782Slinton case O_GTF: 2396086Slinton push(Boolean, fr0 > fr1); 2405782Slinton break; 2415543Slinton 2425782Slinton case O_EQ: 2436086Slinton push(Boolean, r0 == r1); 2445782Slinton break; 2455543Slinton 2465782Slinton case O_EQF: 2476086Slinton push(Boolean, fr0 == fr1); 2485782Slinton break; 2495543Slinton 2505782Slinton case O_NE: 2516086Slinton push(Boolean, r0 != r1); 2525782Slinton break; 2535543Slinton 2545782Slinton case O_NEF: 2556086Slinton push(Boolean, fr0 != fr1); 2565782Slinton break; 2575543Slinton 2585782Slinton case O_AND: 2596086Slinton push(Boolean, r0 && r1); 2605782Slinton break; 2615543Slinton 2625782Slinton case O_OR: 2636086Slinton push(Boolean, r0 || r1); 2645782Slinton break; 2655543Slinton 2665782Slinton case O_ASSIGN: 2675782Slinton assign(p->left, p->right); 2685782Slinton break; 2695543Slinton 2705782Slinton case O_CHFILE: 2715782Slinton if (p->sconval == NIL) { 2725782Slinton printf("%s\n", cursource); 2735782Slinton } else { 2746874Slinton fp = fopen(p->sconval, "r"); 2756874Slinton if (fp == NIL) { 2766874Slinton error("can't read \"%s\"", p->sconval); 2776874Slinton } else { 2786874Slinton fclose(fp); 2796874Slinton skimsource(p->sconval); 2806874Slinton } 2815782Slinton } 2825782Slinton break; 2835543Slinton 2845782Slinton case O_CONT: 2855782Slinton cont(); 2865782Slinton printnews(); 2875782Slinton break; 2885543Slinton 2895782Slinton case O_LIST: { 2905782Slinton SYM *b; 2916083Slinton ADDRESS addr; 2925543Slinton 2935782Slinton if (p->left->op == O_NAME) { 2945782Slinton b = p->left->nameval; 2955782Slinton if (!isblock(b)) { 2965782Slinton error("\"%s\" is not a procedure or function", name(b)); 2975543Slinton } 2986083Slinton addr = firstline(b); 2996083Slinton if (addr == -1) { 3006083Slinton error("\"%s\" is empty", name(b)); 3016083Slinton } 3026083Slinton skimsource(srcfilename(addr)); 3036083Slinton r0 = srcline(addr); 3045782Slinton r1 = r0 + 5; 3055782Slinton if (r1 > lastlinenum) { 3065782Slinton r1 = lastlinenum; 3075782Slinton } 3085782Slinton r0 = r0 - 5; 3095782Slinton if (r0 < 1) { 3105782Slinton r0 = 1; 3115782Slinton } 3125782Slinton } else { 3135782Slinton eval(p->left->right); 3145782Slinton eval(p->left->left); 3155782Slinton r0 = pop(long); 3165782Slinton r1 = pop(long); 3175782Slinton } 3185782Slinton printlines((LINENO) r0, (LINENO) r1); 3195782Slinton break; 3205782Slinton } 3215543Slinton 3225782Slinton case O_XI: 3235782Slinton case O_XD: 3245782Slinton { 3255782Slinton SYM *b; 3265543Slinton 3275782Slinton if (p->left->op == O_CALL) { 3285782Slinton b = p->left->left->nameval; 3295782Slinton r0 = codeloc(b); 3305782Slinton r1 = firstline(b); 3315782Slinton } else { 3325782Slinton eval(p->left->right); 3335782Slinton eval(p->left->left); 3345782Slinton r0 = pop(long); 3355782Slinton r1 = pop(long); 3365782Slinton } 3375782Slinton if (p->op == O_XI) { 3385782Slinton printinst((ADDRESS) r0, (ADDRESS) r1); 3395782Slinton } else { 3405782Slinton printdata((ADDRESS) r0, (ADDRESS) r1); 3415782Slinton } 3425782Slinton break; 3435782Slinton } 3445543Slinton 3455782Slinton case O_NEXT: 3465782Slinton next(); 3475782Slinton printnews(); 3485782Slinton break; 3495543Slinton 3505782Slinton case O_PRINT: { 3515782Slinton NODE *o; 3525543Slinton 3535782Slinton for (o = p->left; o != NIL; o = o->right) { 3545782Slinton eval(o->left); 3555782Slinton printval(o->left->nodetype); 3565782Slinton putchar(' '); 3575782Slinton } 3585782Slinton putchar('\n'); 3595782Slinton break; 3605782Slinton } 3615543Slinton 3625782Slinton case O_STEP: 3635782Slinton stepc(); 3645782Slinton printnews(); 3655782Slinton break; 3665543Slinton 3675782Slinton case O_WHATIS: 3685782Slinton if (p->left->op == O_NAME) { 3695782Slinton printdecl(p->left->nameval); 3705782Slinton } else { 3715782Slinton printdecl(p->left->nodetype); 3725782Slinton } 3735782Slinton break; 3745543Slinton 3755782Slinton case O_WHICH: 3765782Slinton printwhich(p->nameval); 3775782Slinton putchar('\n'); 3785782Slinton break; 3795543Slinton 3805782Slinton case O_WHERE: 3815782Slinton where(); 3825782Slinton break; 3835543Slinton 3845782Slinton case O_ALIAS: 3855782Slinton alias(p->left->sconval, p->right->sconval); 3865782Slinton break; 3875543Slinton 3885782Slinton case O_CALL: 3895782Slinton callproc(p->left, p->right); 3905782Slinton break; 3915543Slinton 3925782Slinton case O_EDIT: 3935782Slinton edit(p->sconval); 3945782Slinton break; 3955543Slinton 3965782Slinton case O_DUMP: 3975782Slinton dump(); 3985782Slinton break; 3995543Slinton 4005782Slinton case O_GRIPE: 4015782Slinton gripe(); 4025782Slinton break; 4035562Slinton 4045782Slinton case O_HELP: 4055782Slinton help(); 4065782Slinton break; 4075543Slinton 4085782Slinton case O_REMAKE: 4095782Slinton remake(); 4105782Slinton break; 4115543Slinton 4125782Slinton case O_RUN: 4135782Slinton run(); 4145782Slinton break; 4155543Slinton 4165782Slinton case O_SOURCE: 4175782Slinton setinput(p->sconval); 4185782Slinton break; 4195543Slinton 4205782Slinton case O_STATUS: 4215782Slinton status(); 4225782Slinton break; 4235543Slinton 4245782Slinton case O_TRACE: 4255782Slinton case O_TRACEI: 4265782Slinton trace(p->op, p->what, p->where, p->cond); 4275782Slinton if (isstdin()) { 4285782Slinton status(); 4295782Slinton } 4305782Slinton break; 4315543Slinton 4325782Slinton case O_STOP: 4335782Slinton case O_STOPI: 4345782Slinton stop(p->op, p->what, p->where, p->cond); 4355782Slinton if (isstdin()) { 4365782Slinton status(); 4375782Slinton } 4385782Slinton break; 4395543Slinton 4405782Slinton case O_DELETE: 4415782Slinton eval(p->left); 4425782Slinton delbp((unsigned int) pop(long)); 4435782Slinton break; 4445543Slinton 4455782Slinton default: 4465782Slinton panic("eval: bad op %d", p->op); 4475782Slinton } 4485543Slinton } 4495543Slinton 4505543Slinton /* 4515562Slinton * Push "len" bytes onto the expression stack from address "addr" 4525562Slinton * in the process. Normally TRUE is returned, however if there 4535562Slinton * isn't enough room on the stack, rpush returns FALSE. 4545562Slinton */ 4555562Slinton 4565562Slinton BOOLEAN rpush(addr, len) 4575562Slinton ADDRESS addr; 4585562Slinton int len; 4595562Slinton { 4605782Slinton BOOLEAN success; 4615562Slinton 4625782Slinton if (sp + len >= &stack[STACKSIZE]) { 4635782Slinton success = FALSE; 4645782Slinton } else { 4655782Slinton dread(sp, addr, len); 4665782Slinton sp += len; 4675782Slinton success = TRUE; 4685782Slinton } 4695782Slinton return success; 4705562Slinton } 4715562Slinton 4725562Slinton /* 4735782Slinton * Pop an item of the given type which is assumed to be no larger 4745782Slinton * than a long and return it expanded into a long. 4755782Slinton */ 4765782Slinton 4775782Slinton long popsmall(t) 4785782Slinton SYM *t; 4795782Slinton { 4805782Slinton long r; 4815782Slinton 4825782Slinton switch (size(t)) { 4835782Slinton case sizeof(char): 4845782Slinton r = (long) pop(char); 4855782Slinton break; 4865782Slinton 4875782Slinton case sizeof(short): 4885782Slinton r = (long) pop(short); 4895782Slinton break; 4905782Slinton 4915782Slinton case sizeof(long): 4925782Slinton r = pop(long); 4935782Slinton break; 4945782Slinton 49510765Slinton /* 49610765Slinton * A bit of a kludge here. If an array element is a record, 49710765Slinton * the dot operation will be converted into an addition with 49810765Slinton * the record operand having a type whose size may be larger 49910765Slinton * than a word. Now actually this is a pointer, but the subscript 50010765Slinton * operation isn't aware of this, so it's just hacked here. 50110765Slinton * 50210765Slinton * The right thing to do is to make dot directly evaluated 50310765Slinton * instead of changing it into addition. 50410765Slinton */ 5055782Slinton default: 50610765Slinton r = pop(ADDRESS); 50710765Slinton break; 5085782Slinton } 5095782Slinton return r; 5105782Slinton } 5115782Slinton 5125782Slinton /* 5135543Slinton * evaluate a conditional expression 5145543Slinton */ 5155543Slinton 5165543Slinton BOOLEAN cond(p) 5175543Slinton NODE *p; 5185543Slinton { 5195782Slinton if (p == NIL) { 5205782Slinton return(TRUE); 5215782Slinton } 5225782Slinton eval(p); 5235782Slinton return(pop(BOOLEAN)); 5245543Slinton } 5255543Slinton 5265543Slinton /* 5275543Slinton * Return the address corresponding to a given tree. 5285543Slinton */ 5295543Slinton 5305543Slinton ADDRESS lval(p) 5315543Slinton NODE *p; 5325543Slinton { 5335782Slinton eval(p); 5345782Slinton return(pop(ADDRESS)); 5355543Slinton } 536