📄 eval.c
字号:
/* * Copyright (c) 1983 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)eval.c 5.7 (Berkeley) 6/1/90";#endif /* not lint *//* * Tree evaluation. */#include "defs.h"#include "tree.h"#include "operators.h"#include "debug.h"#include "eval.h"#include "events.h"#include "symbols.h"#include "scanner.h"#include "source.h"#include "object.h"#include "mappings.h"#include "process.h"#include "runtime.h"#include "machine.h"#include <signal.h>#ifndef public#include "machine.h"#define STACKSIZE 20000typedef Char Stack;#define push(type, value) { \ ((type *) (sp += sizeof(type)))[-1] = (value); \}#define pop(type) ( \ (*((type *) (sp -= sizeof(type)))) \)#define popn(n, dest) { \ sp -= n; \ bcopy(sp, dest, n); \}#define alignstack() { \ sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \}#endifpublic Stack stack[STACKSIZE];public Stack *sp = &stack[0];public Boolean useInstLoc = false;#define chksp() \{ \ if (sp < &stack[0]) { \ panic("stack underflow"); \ } \}#define poparg(n, r, fr) { \ eval(p->value.arg[n]); \ if (isreal(p->op)) { \ if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \ fr = pop(float); \ } else { \ fr = pop(double); \ } \ } else if (isint(p->op)) { \ r = popsmall(p->value.arg[n]->nodetype); \ } \}#define Boolrep char /* underlying representation type for booleans *//* * Command-level evaluation. */public Node topnode;public topeval (p)Node p;{ if (traceeval) { fprintf(stderr, "topeval("); prtree(stderr, p); fprintf(stderr, ")\n"); fflush(stderr); } topnode = p; eval(p);}/* * Evaluate a parse tree leaving the value on the top of the stack. */public eval(p)register Node p;{ long r0, r1; double fr0, fr1; Address addr; long i, n; int len; Symbol s; Node n1, n2; boolean b; File file; String str; checkref(p); if (traceeval) { fprintf(stderr, "begin eval %s\n", opname(p->op)); } switch (degree(p->op)) { case BINARY: poparg(1, r1, fr1); poparg(0, r0, fr0); break; case UNARY: poparg(0, r0, fr0); break; default: /* do nothing */; } switch (p->op) { case O_SYM: s = p->value.sym; if (s == retaddrsym) { push(long, return_addr()); } else if (isvariable(s)) { if (s != program and not isactive(container(s))) { error("\"%s\" is not active", symname(s)); } if (isvarparam(s) and not isopenarray(s)) { rpush(address(s, nil), sizeof(Address)); } else { push(Address, address(s, nil)); } } else if (isblock(s)) { push(Symbol, s); } else if (isconst(s)) { eval(constval(s)); } else { error("can't evaluate a %s", classname(s)); } break; case O_LCON: case O_CCON: r0 = p->value.lcon; pushsmall(p->nodetype, r0); break; case O_FCON: push(double, p->value.fcon); break; case O_SCON: len = size(p->nodetype); mov(p->value.scon, sp, len); sp += len; break; case O_INDEX: s = p->value.arg[0]->nodetype; p->value.arg[0]->nodetype = t_addr; eval(p->value.arg[0]); p->value.arg[0]->nodetype = s; n = pop(Address); eval(p->value.arg[1]); evalindex(s, n, popsmall(p->value.arg[1]->nodetype)); break; case O_DOT: s = p->value.arg[1]->value.sym; eval(p->value.arg[0]); n = pop(long); push(long, n + (s->symvalue.field.offset div 8)); break; /* * Get the value of the expression addressed by the top of the stack. * Push the result back on the stack. */ case O_INDIR: case O_RVAL: addr = pop(long); if (addr == 0) { error("reference through nil pointer"); } len = size(p->nodetype); rpush(addr, len); break; case O_TYPERENAME: loophole(size(p->value.arg[0]->nodetype), size(p->nodetype)); break; case O_COMMA: eval(p->value.arg[0]); if (p->value.arg[1] != nil) { eval(p->value.arg[1]); } break; case O_ITOF: push(double, (double) r0); break; case O_ADD: push(long, r0+r1); break; case O_ADDF: push(double, fr0+fr1); break; case O_SUB: push(long, r0-r1); break; case O_SUBF: push(double, fr0-fr1); break; case O_NEG: push(long, -r0); break; case O_NEGF: push(double, -fr0); break; case O_MUL: push(long, r0*r1); break; case O_MULF: push(double, fr0*fr1); break; case O_DIVF: if (fr1 == 0) { error("error: division by 0"); } push(double, fr0 / fr1); break; case O_DIV: if (r1 == 0) { error("error: div by 0"); } push(long, r0 div r1); break; case O_MOD: if (r1 == 0) { error("error: mod by 0"); } push(long, r0 mod r1); break; case O_LT: push(Boolrep, r0 < r1); break; case O_LTF: push(Boolrep, fr0 < fr1); break; case O_LE: push(Boolrep, r0 <= r1); break; case O_LEF: push(Boolrep, fr0 <= fr1); break; case O_GT: push(Boolrep, r0 > r1); break; case O_GTF: push(Boolrep, fr0 > fr1); break; case O_EQ: push(Boolrep, r0 == r1); break; case O_EQF: push(Boolrep, fr0 == fr1); break; case O_NE: push(Boolrep, r0 != r1); break; case O_NEF: push(Boolrep, fr0 != fr1); break; case O_AND: push(Boolrep, r0 and r1); break; case O_OR: push(Boolrep, r0 or r1); break; case O_ASSIGN: assign(p->value.arg[0], p->value.arg[1]); break; case O_CHFILE: if (p->value.scon == nil) { printf("%s\n", cursource); } else { file = opensource(p->value.scon); if (file == nil) { error("can't read \"%s\"", p->value.scon); } else { fclose(file); setsource(p->value.scon); } } break; case O_CONT: cont(p->value.lcon); printnews(); break; case O_LIST: list(p); break; case O_FUNC: func(p->value.arg[0]); break; case O_EXAMINE: eval(p->value.examine.beginaddr); r0 = pop(long); if (p->value.examine.endaddr == nil) { n = p->value.examine.count; if (n == 0) { printvalue(r0, p->value.examine.mode); } else if (streq(p->value.examine.mode, "i")) { printninst(n, (Address) r0); } else { printndata(n, (Address) r0, p->value.examine.mode); } } else { eval(p->value.examine.endaddr); r1 = pop(long); if (streq(p->value.examine.mode, "i")) { printinst((Address)r0, (Address)r1); } else { printdata((Address)r0, (Address)r1, p->value.examine.mode); } } break; case O_PRINT: for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) { eval(n1->value.arg[0]); printval(n1->value.arg[0]->nodetype); putchar(' '); } putchar('\n'); break; case O_PSYM: if (p->value.arg[0]->op == O_SYM) { psym(p->value.arg[0]->value.sym); } else { psym(p->value.arg[0]->nodetype); } break; case O_QLINE: eval(p->value.arg[1]); break; case O_STEP: b = inst_tracing; inst_tracing = (Boolean) (not p->value.step.source); if (p->value.step.skipcalls) { next(); } else { stepc(); } inst_tracing = b; useInstLoc = (Boolean) (not p->value.step.source); printnews(); break; case O_WHATIS: if (p->value.arg[0]->op == O_SYM) { printdecl(p->value.arg[0]->value.sym); } else { printdecl(p->value.arg[0]->nodetype); } break; case O_WHERE: wherecmd(); break; case O_WHEREIS: if (p->value.arg[0]->op == O_SYM) { printwhereis(stdout, p->value.arg[0]->value.sym); } else { printwhereis(stdout, p->value.arg[0]->nodetype); } break; case O_WHICH: if (p->value.arg[0]->op == O_SYM) { printwhich(stdout, p->value.arg[0]->value.sym); } else { printwhich(stdout, p->value.arg[0]->nodetype); } putchar('\n'); break; case O_ALIAS: n1 = p->value.arg[0]; n2 = p->value.arg[1]; if (n2 == nil) { if (n1 == nil) { alias(nil, nil, nil); } else { alias(n1->value.name, nil, nil); } } else if (n2->op == O_NAME) { str = ident(n2->value.name); alias(n1->value.name, nil, strdup(str)); } else { if (n1->op == O_COMMA) { alias( n1->value.arg[0]->value.name, (List) n1->value.arg[1], n2->value.scon ); } else { alias(n1->value.name, nil, n2->value.scon); } } break; case O_UNALIAS: unalias(p->value.arg[0]->value.name); break; case O_CALLPROC: callproc(p, false); break; case O_CALL: callproc(p, true); break; case O_CATCH: if (p->value.lcon == 0) { printsigscaught(process); } else { psigtrace(process, p->value.lcon, true); } break; case O_EDIT: edit(p->value.scon); break; case O_DEBUG: debug(p); break; case O_DOWN: checkref(p->value.arg[0]); assert(p->value.arg[0]->op == O_LCON); down(p->value.arg[0]->value.lcon); break; case O_DUMP: if (p->value.arg[0] == nil) { dumpall(); } else { s = p->value.arg[0]->value.sym; if (s == curfunc) { dump(nil); } else { dump(s); } } break; case O_GRIPE: gripe(); break; case O_HELP: help(); break; case O_IGNORE: if (p->value.lcon == 0) { printsigsignored(process); } else { psigtrace(process, p->value.lcon, false); } break; case O_RETURN: if (p->value.arg[0] == nil) { rtnfunc(nil); } else { assert(p->value.arg[0]->op == O_SYM); rtnfunc(p->value.arg[0]->value.sym); } break; case O_RUN: run(); break; case O_SET: set(p->value.arg[0], p->value.arg[1]); break; case O_SEARCH: search(p->value.arg[0]->value.lcon, p->value.arg[1]->value.scon); break; case O_SOURCE: setinput(p->value.scon); break; case O_STATUS: status(); break; case O_TRACE: case O_TRACEI: trace(p); break; case O_STOP: case O_STOPI: stop(p); break; case O_UNSET: undefvar(p->value.arg[0]->value.name); break; case O_UP: checkref(p->value.arg[0]); assert(p->value.arg[0]->op == O_LCON); up(p->value.arg[0]->value.lcon); break; case O_ADDEVENT: addevent(p->value.event.cond, p->value.event.actions); break; case O_DELETE: n1 = p->value.arg[0]; while (n1->op == O_COMMA) { n2 = n1->value.arg[0]; assert(n2->op == O_LCON); if (not delevent((unsigned int) n2->value.lcon)) { error("unknown event %ld", n2->value.lcon); } n1 = n1->value.arg[1]; } assert(n1->op == O_LCON); if (not delevent((unsigned int) n1->value.lcon)) { error("unknown event %ld", n1->value.lcon); } break; case O_ENDX: endprogram(); break; case O_IF: if (cond(p->value.event.cond)) { evalcmdlist(p->value.event.actions); } break; case O_ONCE: event_once(p->value.event.cond, p->value.event.actions); break; case O_PRINTCALL: printcall(p->value.sym, whatblock(return_addr())); break; case O_PRINTIFCHANGED: printifchanged(p->value.arg[0]); break; case O_PRINTRTN: printrtn(p->value.sym); break; case O_PRINTSRCPOS: getsrcpos(); if (p->value.arg[0] == nil) { printsrcpos(); putchar('\n'); printlines(curline, curline); } else if (p->value.arg[0]->op == O_QLINE) { if (p->value.arg[0]->value.arg[1]->value.lcon == 0) { printf("tracei: "); printinst(pc, pc); } else { if (canReadSource()) { printf("trace: "); printlines(curline, curline); } } } else { printsrcpos(); printf(": "); eval(p->value.arg[0]); prtree(stdout, p->value.arg[0]); printf(" = "); printval(p->value.arg[0]->nodetype); putchar('\n'); } break; case O_PROCRTN: procreturn(p->value.sym); break; case O_STOPIFCHANGED: stopifchanged(p->value.arg[0]); break; case O_STOPX: isstopped = true; break; case O_TRACEON: traceon(p->value.trace.inst, p->value.trace.event, p->value.trace.actions); break; case O_TRACEOFF: traceoff(p->value.lcon); break; default: panic("eval: bad op %d", p->op); } if (traceeval) { fprintf(stderr, "end eval %s\n", opname(p->op));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -