1*47822Sbostic /*-
2*47822Sbostic * Copyright (c) 1991 The Regents of the University of California.
3*47822Sbostic * All rights reserved.
4*47822Sbostic *
5*47822Sbostic * %sccs.include.proprietary.c%
6*47822Sbostic */
7*47822Sbostic
836559Sbostic #ifndef lint
9*47822Sbostic static char sccsid[] = "@(#)expr.c 5.2 (Berkeley) 04/04/91";
10*47822Sbostic #endif /* not lint */
1136559Sbostic
1236559Sbostic /*
1336559Sbostic * adb - expression parser
1436559Sbostic */
1536559Sbostic
1636559Sbostic #include "defs.h"
1736559Sbostic #include <ctype.h>
1836559Sbostic
1936559Sbostic extern char BADSYM[]; /* "symbol not found" */
2036559Sbostic extern char BADVAR[]; /* "bad variable" */
2136559Sbostic extern char BADSYN[]; /* "syntax error" */
2236559Sbostic extern char NOCFN[]; /* "c routine not found" */
2336559Sbostic extern char NOADR[]; /* "address expected" */
2436559Sbostic extern char BADLOC[]; /* "automatic variable not found" */
2536559Sbostic extern char NOPCS[]; /* "no process" */
2636559Sbostic
2736559Sbostic struct nlist *xxxsym; /* last symbol found due to expression */
2836559Sbostic /* change this name back to cursym AFTER testing!... */
2936559Sbostic struct activation curframe; /* current stack frame (for local vars) */
3036559Sbostic
3136559Sbostic /*
3236559Sbostic * This file implements a small recursive descent expression parser.
3336559Sbostic * The syntax is (in YACC terms):
3436559Sbostic *
3536559Sbostic * expr : expr1
3636559Sbostic * | (empty)
3736559Sbostic * ;
3836559Sbostic *
3936559Sbostic * expr1 : term
4036559Sbostic * | term dyadic expr1
4136559Sbostic * ;
4236559Sbostic *
4336559Sbostic * dyadic : '+' (addition)
4436559Sbostic * | '-' (subtraction)
4536559Sbostic * | '#' (roundup)
4636559Sbostic * | '*' (multiplication)
4736559Sbostic * | '%' (division)
4836559Sbostic * | '&' (bitwise and)
4936559Sbostic * | '|' (bitwise or)
5036559Sbostic * ;
5136559Sbostic *
5236559Sbostic * term : item
5336559Sbostic * | monadic term
5436559Sbostic * | '(' expr ')'
5536559Sbostic * ;
5636559Sbostic *
5736559Sbostic * monadic : '*' (contents of core, or SP_DATA)
5836559Sbostic * | '@' (contents of a.out, or SP_INSTR)
5936559Sbostic * | '-' (negation)
6036559Sbostic * | '~' (bitwise not)
6136559Sbostic * | '#' (logical not)
6236559Sbostic * ;
6336559Sbostic *
6436559Sbostic * item : number (current radix; 0o,0t,0x; or float)
6536559Sbostic * | name (value from symbol table)
6636559Sbostic * | rtn '.' name (address of name in routine rtn)
6736559Sbostic * | rtn '.' (???)
6836559Sbostic * | '.' name (???)
6936559Sbostic * | '.' (value of dot)
7036559Sbostic * | '+' (dot + current increment)
7136559Sbostic * | '^' (dot - current increment)
7236559Sbostic * | '"' (last address typed)
7336559Sbostic * | '<' var (value of variable var)
7436559Sbostic * | '<' register (value in register)
7536559Sbostic * | '\'' ch '\'' (character(s))
7636559Sbostic * ;
7736559Sbostic *
7836559Sbostic * The empty string handling is actually done in `item', but callers
7936559Sbostic * can simply assume that expr() returns 1 if it finds an expression,
8036559Sbostic * or 0 if not, and that rexpr() errors out if there is no expression.
8136559Sbostic *
8236559Sbostic * The routines symchar() and getsym() handle `name's and `rtn's.
8336559Sbostic * The routine getnum(), with helper getfloat(), handles `number's.
8436559Sbostic */
8536559Sbostic
8636559Sbostic /* flags for symchar() */
8736559Sbostic #define SYMCH_READ 1 /* call readchar() first */
8836559Sbostic #define SYMCH_DIGITS 2 /* allow digits */
8936559Sbostic
9036559Sbostic /*
9136559Sbostic * Return true if the next (how & SYMCH_READ) or current character
9236559Sbostic * is a symbol character; allow digits if (how & SYMCH_DIGITS).
9336559Sbostic */
9436559Sbostic static int
symchar(how)9536559Sbostic symchar(how)
9636559Sbostic int how;
9736559Sbostic {
9836559Sbostic
9936559Sbostic if (how & SYMCH_READ)
10036559Sbostic (void) readchar();
10136559Sbostic if (lastc == '\\') {
10236559Sbostic (void) readchar();
10336559Sbostic return (1);
10436559Sbostic }
10536559Sbostic if (isalpha(lastc) || lastc == '_')
10636559Sbostic return (1);
10736559Sbostic return ((how & SYMCH_DIGITS) && isdigit(lastc));
10836559Sbostic }
10936559Sbostic
11036559Sbostic /*
11136559Sbostic * Read a symbol into the given buffer. The first character is
11236559Sbostic * assumed already to have been read.
11336559Sbostic */
11436559Sbostic static
getsym(symbuf,symlen)11536559Sbostic getsym(symbuf, symlen)
11636559Sbostic register char *symbuf;
11736559Sbostic register int symlen;
11836559Sbostic {
11936559Sbostic
12036559Sbostic do {
12136559Sbostic if (--symlen > 0)
12236559Sbostic *symbuf++ = lastc;
12336559Sbostic } while (symchar(SYMCH_READ | SYMCH_DIGITS));
12436559Sbostic *symbuf = 0;
12536559Sbostic }
12636559Sbostic
12736559Sbostic /*
12836559Sbostic * Read a number. The converted value is stored in expv.
12936559Sbostic * The caller has already determined that there is at least one digit.
13036559Sbostic */
13136559Sbostic static
getnum()13236559Sbostic getnum()
13336559Sbostic {
13436559Sbostic register int base, c;
13536559Sbostic
13636559Sbostic expv = 0;
13736559Sbostic if ((base = radix) < 0)
13836559Sbostic base = -base;
13936559Sbostic if (lastc == '0') {
14036559Sbostic switch (readchar()) {
14136559Sbostic case 'x': case 'X':
14236559Sbostic base = 16;
14336559Sbostic (void) readchar();
14436559Sbostic break;
14536559Sbostic case 't': case 'T':
14636559Sbostic base = 10;
14736559Sbostic (void) readchar();
14836559Sbostic break;
14936559Sbostic case 'o': case 'O':
15036559Sbostic base = 8;
15136559Sbostic (void) readchar();
15236559Sbostic }
15336559Sbostic }
15436559Sbostic for (c = lastc; isxdigit(c); c = readchar()) {
15536559Sbostic if (isdigit(c))
15636559Sbostic c -= '0';
15736559Sbostic else if (base <= 10)
15836559Sbostic break;
15936559Sbostic else
16036559Sbostic c -= isupper(c) ? 'A' - 10 : 'a' - 10;
16136559Sbostic if (c >= base)
16236559Sbostic error(BADSYN);
16336559Sbostic /* since expv is unsigned, the following cannot overflow */
16436559Sbostic expv = expv * base + c;
16536559Sbostic }
16636559Sbostic if (lastc == '.' && (base == 10 || expv == 0))
16736559Sbostic getfloat();
16836559Sbostic unreadc();
16936559Sbostic }
17036559Sbostic
17136559Sbostic /*
17236559Sbostic * Read a float. The integer part is already in expv. Set expv
17336559Sbostic * to the integer bit pattern that corresponds to the float.
17436559Sbostic *
17536559Sbostic * The following routine could be improved, but at least it will
17636559Sbostic * not crash on input such as 0.999999999999999999999999999999,
17736559Sbostic * as did the original.
17836559Sbostic */
getfloat()17936559Sbostic getfloat()
18036559Sbostic {
18136559Sbostic register int i;
18236559Sbostic register char *p;
18336559Sbostic /* THE FOLLOWING ASSUMES sizeof(float)==sizeof(expr_t) */
18436559Sbostic /* PERHAPS THIS SHOULD BE MOVED TO MACHINE DEPENDENT CODE */
18536559Sbostic union {
18636559Sbostic float r;
18736559Sbostic expr_t e;
18836559Sbostic } gross;
18936559Sbostic /* end machine dependent */
19036559Sbostic char hackbuf[50];
19136559Sbostic double atof();
19236559Sbostic
19336559Sbostic for (i = sizeof(hackbuf), p = hackbuf; isdigit(readchar());)
19436559Sbostic if (--i > 0)
19536559Sbostic *p++ = lastc;
19636559Sbostic *p = 0;
19736559Sbostic gross.r = expv + atof(hackbuf);
19836559Sbostic expv = gross.e;
19936559Sbostic }
20036559Sbostic
20136559Sbostic /*
20236559Sbostic * item : number | name [ '.' local ] | '.' local | '.' | '+' | '^' | '"' |
20336559Sbostic * '<' var | '<' register | '\'' char(s) '\'' ;
20436559Sbostic *
20536559Sbostic * item returns 1 if it finds an item, or 0 if it resolves to
20636559Sbostic * the empty string.
20736559Sbostic */
20836559Sbostic static int
item(allownil)20936559Sbostic item(allownil)
21036559Sbostic int allownil;
21136559Sbostic {
21236559Sbostic register int i, c;
21336559Sbostic struct reglist *reg;
21436559Sbostic
21536559Sbostic c = readchar();
21636559Sbostic if (isdigit(c)) {
21736559Sbostic getnum();
21836559Sbostic return (1);
21936559Sbostic }
22036559Sbostic if (symchar(0)) {
22136559Sbostic ev_name();
22236559Sbostic return (1);
22336559Sbostic }
22436559Sbostic switch (c) {
22536559Sbostic
22636559Sbostic case '.':
22736559Sbostic if (symchar(SYMCH_READ))
22836559Sbostic ev_local(); /* SHOULD RESET xxxsym FIRST? */
22936559Sbostic else
23036559Sbostic expv = dot;
23136559Sbostic unreadc();
23236559Sbostic return (1);
23336559Sbostic
23436559Sbostic case '"':
23536559Sbostic expv = ditto;
23636559Sbostic return (1);
23736559Sbostic
23836559Sbostic case '+':
23936559Sbostic expv = inkdot(dotinc);
24036559Sbostic return (1);
24136559Sbostic
24236559Sbostic case '^':
24336559Sbostic expv = inkdot(-dotinc);
24436559Sbostic return (1);
24536559Sbostic
24636559Sbostic case '<':
24736559Sbostic if ((reg = reglookup()) != NULL) {
24836559Sbostic expv = getreg(reg);
24936559Sbostic return (1);
25036559Sbostic }
25136559Sbostic else if ((i = varlookup(rdc())) != -1)
25236559Sbostic expv = var[i];
25336559Sbostic else
25436559Sbostic error(BADVAR);
25536559Sbostic return (1);
25636559Sbostic
25736559Sbostic case '\'':
25836559Sbostic i = sizeof(expr_t) / sizeof(char);
25936559Sbostic for (expv = 0;; expv = (expv << NBBY) | c) {
26036559Sbostic if ((c = readchar()) == '\\') {
26136559Sbostic if ((c = readchar()) == 0)
26236559Sbostic break;
26336559Sbostic } else if (c == '\'')
26436559Sbostic break;
26536559Sbostic if (--i < 0)
26636559Sbostic error(BADSYN);
26736559Sbostic }
26836559Sbostic return (1);
26936559Sbostic }
27036559Sbostic if (!allownil)
27136559Sbostic error(NOADR);
27236559Sbostic unreadc();
27336559Sbostic return (0);
27436559Sbostic }
27536559Sbostic
27636559Sbostic /*
27736559Sbostic * term : item | monadic_op term | '(' expr ')' ;
27836559Sbostic */
term(allownil)27936559Sbostic term(allownil)
28036559Sbostic int allownil;
28136559Sbostic {
28236559Sbostic
28336559Sbostic switch (readchar()) {
28436559Sbostic
28536559Sbostic case '*':
28636559Sbostic case '@':
28736559Sbostic (void) term(0);
28836559Sbostic (void) adbread(lastc == '@' ? SP_INSTR : SP_DATA,
28936559Sbostic (addr_t)expv, (caddr_t)&expv, sizeof(expv));
29036559Sbostic checkerr();
29136559Sbostic return (1);
29236559Sbostic
29336559Sbostic case '-':
29436559Sbostic (void) term(0);
29536559Sbostic expv = -expv;
29636559Sbostic return (1);
29736559Sbostic
29836559Sbostic case '~':
29936559Sbostic (void) term(0);
30036559Sbostic expv = ~expv;
30136559Sbostic return (1);
30236559Sbostic
30336559Sbostic case '#':
30436559Sbostic (void) term(0);
30536559Sbostic expv = !expv;
30636559Sbostic return (1);
30736559Sbostic
30836559Sbostic case '(':
30936559Sbostic (void) iexpr(0);
31036559Sbostic if (readchar() != ')')
31136559Sbostic error(BADSYN);
31236559Sbostic return (1);
31336559Sbostic
31436559Sbostic default:
31536559Sbostic unreadc();
31636559Sbostic return (item(allownil));
31736559Sbostic }
31836559Sbostic }
31936559Sbostic
32036559Sbostic /*
32136559Sbostic * expr : term | term dyadic expr | ;
32236559Sbostic * (internal version, which passes on the allow-nil flag)
32336559Sbostic */
32436559Sbostic static int
iexpr(allownil)32536559Sbostic iexpr(allownil)
32636559Sbostic int allownil;
32736559Sbostic {
32836559Sbostic register expr_t lhs, t;
32936559Sbostic
33036559Sbostic (void) rdc();
33136559Sbostic unreadc();
33236559Sbostic if (!term(allownil))
33336559Sbostic return (0);
33436559Sbostic for (;;) {
33536559Sbostic lhs = expv;
33636559Sbostic switch (readchar()) {
33736559Sbostic
33836559Sbostic case '+':
33936559Sbostic (void) term(0);
34036559Sbostic expv += lhs;
34136559Sbostic break;
34236559Sbostic
34336559Sbostic case '-':
34436559Sbostic (void) term(0);
34536559Sbostic expv = lhs - expv;
34636559Sbostic break;
34736559Sbostic
34836559Sbostic case '#':
34936559Sbostic (void) term(0);
35036559Sbostic if (expv == 0)
35136559Sbostic error("# by 0");
35236559Sbostic /* roundup(lhs, expv), but careful about overflow */
35336559Sbostic t = lhs / expv;
35436559Sbostic t *= expv;
35536559Sbostic expv = t == lhs ? t : t + expv;
35636559Sbostic break;
35736559Sbostic
35836559Sbostic case '*':
35936559Sbostic (void) term(0);
36036559Sbostic expv *= lhs;
36136559Sbostic break;
36236559Sbostic
36336559Sbostic case '%':
36436559Sbostic (void) term(0);
36536559Sbostic expv = lhs / expv;
36636559Sbostic break;
36736559Sbostic
36836559Sbostic case '&':
36936559Sbostic (void) term(0);
37036559Sbostic expv &= lhs;
37136559Sbostic break;
37236559Sbostic
37336559Sbostic case '|':
37436559Sbostic (void) term(0);
37536559Sbostic expv |= lhs;
37636559Sbostic break;
37736559Sbostic
37836559Sbostic default:
37936559Sbostic unreadc();
38036559Sbostic return (1);
38136559Sbostic }
38236559Sbostic }
38336559Sbostic }
38436559Sbostic
38536559Sbostic int
oexpr()38636559Sbostic oexpr()
38736559Sbostic {
38836559Sbostic
38936559Sbostic return (iexpr(1));
39036559Sbostic }
39136559Sbostic
39236559Sbostic expr_t
rexpr()39336559Sbostic rexpr()
39436559Sbostic {
39536559Sbostic
39636559Sbostic (void) iexpr(0);
39736559Sbostic return (expv);
39836559Sbostic }
39936559Sbostic
40036559Sbostic /*
40136559Sbostic * Evaluate a name, or a name '.' localname.
40236559Sbostic */
40336559Sbostic static
ev_name()40436559Sbostic ev_name()
40536559Sbostic {
40636559Sbostic struct nlist *symp;
40736559Sbostic char symbuf[SYMLEN];
40836559Sbostic
40936559Sbostic /* name [ . localname ] */
41036559Sbostic getsym(symbuf, sizeof(symbuf));
41136559Sbostic if (lastc == '.') /* name . local */
41236559Sbostic find_frame(symbuf);
41336559Sbostic else if ((symp = lookup(symbuf)) != NULL)
41436559Sbostic expv = (xxxsym = symp)->n_value;
41536559Sbostic else
41636559Sbostic error(BADSYM);
41736559Sbostic unreadc();
41836559Sbostic }
41936559Sbostic
42036559Sbostic /*
42136559Sbostic * Backtrack through the call stack to find the symbol in symbuf.
42236559Sbostic * Save the result, and if there is another name, look for it within
42336559Sbostic * that frame. Otherwise the value of the expression is the address
42436559Sbostic * of the found frame.
42536559Sbostic */
42636559Sbostic static
find_frame(symbuf)42736559Sbostic find_frame(symbuf)
42836559Sbostic char *symbuf;
42936559Sbostic {
43036559Sbostic struct activation a;
43136559Sbostic addr_t dummy; /* for findsym() to scribble on */
43236559Sbostic
43336559Sbostic if (pid == 0)
43436559Sbostic error(NOPCS);
43536559Sbostic for (a_init(&a); a.a_valid; a_back(&a)) {
43636559Sbostic checkerr();
43736559Sbostic if ((xxxsym = findsym(a.a_pc, SP_INSTR, &dummy)) == NULL)
43836559Sbostic break;
43936559Sbostic if (eqsym(xxxsym->n_un.n_name, symbuf, '_')) {
44036559Sbostic curframe = a;
44136559Sbostic if (symchar(SYMCH_READ))
44236559Sbostic ev_local();
44336559Sbostic else
44436559Sbostic expv = a.a_fp;
44536559Sbostic return;
44636559Sbostic }
44736559Sbostic }
44836559Sbostic error(NOCFN);
44936559Sbostic /* NOTREACHED */
45036559Sbostic }
45136559Sbostic
45236559Sbostic /*
45336559Sbostic * Linear search (ugh) for a symbol in the current stack frame.
45436559Sbostic */
45536559Sbostic static
ev_local()45636559Sbostic ev_local()
45736559Sbostic {
45836559Sbostic register struct nlist *sp;
45936559Sbostic register char *a, *b;
46036559Sbostic char symbuf[SYMLEN];
46136559Sbostic
46236559Sbostic if (pid == 0)
46336559Sbostic error(NOPCS);
46436559Sbostic if (!curframe.a_valid || (sp = xxxsym) == NULL)
46536559Sbostic error(NOCFN);
46636559Sbostic getsym(symbuf, SYMLEN);
46736559Sbostic while ((sp = nextlocal(sp)) != NULL) {
46836559Sbostic /*
46936559Sbostic * Local and parameter symbols (as generated by .stabs)
47036559Sbostic * end with ':', not '\0'; here we allow both.
47136559Sbostic */
47236559Sbostic if (*(a = sp->n_un.n_name) != *(b = symbuf))
47336559Sbostic continue;
47436559Sbostic while (*a == *b++)
47536559Sbostic if (*a++ == 0 || *a == ':') {
47636559Sbostic expv = eval_localsym(sp, &curframe);
47736559Sbostic xxxsym = sp; /* ??? */
47836559Sbostic return;
47936559Sbostic }
48036559Sbostic }
48136559Sbostic error(BADLOC);
48236559Sbostic }
48336559Sbostic
48436559Sbostic #ifndef inkdot
48536559Sbostic /*
48636559Sbostic * Function version of inkdot(). Compute the new dot, and check for
48736559Sbostic * address wrap-around.
48836559Sbostic */
48936559Sbostic addr_t
inkdot(incr)49036559Sbostic inkdot(incr)
49136559Sbostic int incr;
49236559Sbostic {
49336559Sbostic addr_t newdot = dot + incr;
49436559Sbostic
49536559Sbostic if (ADDRESS_WRAP(dot, newdot))
49636559Sbostic error(ADWRAP);
49736559Sbostic return (newdot);
49836559Sbostic }
49936559Sbostic #endif
500