static char sccsid
[] = "@(#)expr.c 5.1 (Berkeley) %G%";
* adb - expression parser
extern char BADSYM
[]; /* "symbol not found" */
extern char BADVAR
[]; /* "bad variable" */
extern char BADSYN
[]; /* "syntax error" */
extern char NOCFN
[]; /* "c routine not found" */
extern char NOADR
[]; /* "address expected" */
extern char BADLOC
[]; /* "automatic variable not found" */
extern char NOPCS
[]; /* "no process" */
struct nlist
*xxxsym
; /* last symbol found due to expression */
/* change this name back to cursym AFTER testing!... */
struct activation curframe
; /* current stack frame (for local vars) */
* This file implements a small recursive descent expression parser.
* The syntax is (in YACC terms):
* dyadic : '+' (addition)
* monadic : '*' (contents of core, or SP_DATA)
* | '@' (contents of a.out, or SP_INSTR)
* item : number (current radix; 0o,0t,0x; or float)
* | name (value from symbol table)
* | rtn '.' name (address of name in routine rtn)
* | '+' (dot + current increment)
* | '^' (dot - current increment)
* | '"' (last address typed)
* | '<' var (value of variable var)
* | '<' register (value in register)
* | '\'' ch '\'' (character(s))
* The empty string handling is actually done in `item', but callers
* can simply assume that expr() returns 1 if it finds an expression,
* or 0 if not, and that rexpr() errors out if there is no expression.
* The routines symchar() and getsym() handle `name's and `rtn's.
* The routine getnum(), with helper getfloat(), handles `number's.
/* flags for symchar() */
#define SYMCH_READ 1 /* call readchar() first */
#define SYMCH_DIGITS 2 /* allow digits */
* Return true if the next (how & SYMCH_READ) or current character
* is a symbol character; allow digits if (how & SYMCH_DIGITS).
if (isalpha(lastc
) || lastc
== '_')
return ((how
& SYMCH_DIGITS
) && isdigit(lastc
));
* Read a symbol into the given buffer. The first character is
* assumed already to have been read.
} while (symchar(SYMCH_READ
| SYMCH_DIGITS
));
* Read a number. The converted value is stored in expv.
* The caller has already determined that there is at least one digit.
for (c
= lastc
; isxdigit(c
); c
= readchar()) {
c
-= isupper(c
) ? 'A' - 10 : 'a' - 10;
/* since expv is unsigned, the following cannot overflow */
if (lastc
== '.' && (base
== 10 || expv
== 0))
* Read a float. The integer part is already in expv. Set expv
* to the integer bit pattern that corresponds to the float.
* The following routine could be improved, but at least it will
* not crash on input such as 0.999999999999999999999999999999,
/* THE FOLLOWING ASSUMES sizeof(float)==sizeof(expr_t) */
/* PERHAPS THIS SHOULD BE MOVED TO MACHINE DEPENDENT CODE */
/* end machine dependent */
for (i
= sizeof(hackbuf
), p
= hackbuf
; isdigit(readchar());)
gross
.r
= expv
+ atof(hackbuf
);
* item : number | name [ '.' local ] | '.' local | '.' | '+' | '^' | '"' |
* '<' var | '<' register | '\'' char(s) '\'' ;
* item returns 1 if it finds an item, or 0 if it resolves to
ev_local(); /* SHOULD RESET xxxsym FIRST? */
if ((reg
= reglookup()) != NULL
) {
else if ((i
= varlookup(rdc())) != -1)
i
= sizeof(expr_t
) / sizeof(char);
for (expv
= 0;; expv
= (expv
<< NBBY
) | c
) {
if ((c
= readchar()) == '\\') {
if ((c
= readchar()) == 0)
* term : item | monadic_op term | '(' expr ')' ;
(void) adbread(lastc
== '@' ? SP_INSTR
: SP_DATA
,
(addr_t
)expv
, (caddr_t
)&expv
, sizeof(expv
));
* expr : term | term dyadic expr | ;
* (internal version, which passes on the allow-nil flag)
/* roundup(lhs, expv), but careful about overflow */
expv
= t
== lhs
? t
: t
+ expv
;
* Evaluate a name, or a name '.' localname.
/* name [ . localname ] */
getsym(symbuf
, sizeof(symbuf
));
if (lastc
== '.') /* name . local */
else if ((symp
= lookup(symbuf
)) != NULL
)
expv
= (xxxsym
= symp
)->n_value
;
* Backtrack through the call stack to find the symbol in symbuf.
* Save the result, and if there is another name, look for it within
* that frame. Otherwise the value of the expression is the address
addr_t dummy
; /* for findsym() to scribble on */
for (a_init(&a
); a
.a_valid
; a_back(&a
)) {
if ((xxxsym
= findsym(a
.a_pc
, SP_INSTR
, &dummy
)) == NULL
)
if (eqsym(xxxsym
->n_un
.n_name
, symbuf
, '_')) {
* Linear search (ugh) for a symbol in the current stack frame.
register struct nlist
*sp
;
if (!curframe
.a_valid
|| (sp
= xxxsym
) == NULL
)
while ((sp
= nextlocal(sp
)) != NULL
) {
* Local and parameter symbols (as generated by .stabs)
* end with ':', not '\0'; here we allow both.
if (*(a
= sp
->n_un
.n_name
) != *(b
= symbuf
))
if (*a
++ == 0 || *a
== ':') {
expv
= eval_localsym(sp
, &curframe
);
* Function version of inkdot(). Compute the new dot, and check for
addr_t newdot
= dot
+ incr
;
if (ADDRESS_WRAP(dot
, newdot
))