debugger
diff --git a/src/cmd/db/expr.c b/src/cmd/db/expr.c
new file mode 100644
index 0000000..8d33e7f
--- /dev/null
+++ b/src/cmd/db/expr.c
@@ -0,0 +1,397 @@
+/*
+ *
+ *	debugger
+ *
+ */
+
+#include "defs.h"
+#include "fns.h"
+
+static long	dbround(long, long);
+
+extern	ADDR	ditto;
+vlong	expv;
+
+static WORD
+ascval(void)
+{
+	Rune r;
+
+	if (readchar() == 0)
+		return (0);
+	r = lastc;
+	while(quotchar())	/*discard chars to ending quote */
+		;
+	return((WORD) r);
+}
+
+/*
+ * read a floating point number
+ * the result must fit in a WORD
+ */
+
+static WORD
+fpin(char *buf)
+{
+	union {
+		WORD w;
+		float f;
+	} x;
+
+	x.f = atof(buf);
+	return (x.w);
+}
+
+WORD
+defval(WORD w)
+{
+	if (expr(0))
+		return (expv);
+	else
+		return (w);
+}
+
+int
+expr(int a)
+{	/* term | term dyadic expr |  */
+	int	rc;
+	WORD	lhs;
+
+	rdc();
+	reread();
+	rc=term(a);
+	while (rc) {
+		lhs = expv;
+		switch ((int)readchar()) {
+
+		case '+':
+			term(a|1);
+			expv += lhs;
+			break;
+
+		case '-':
+			term(a|1);
+			expv = lhs - expv;
+			break;
+
+		case '#':
+			term(a|1);
+			expv = dbround(lhs,expv);
+			break;
+
+		case '*':
+			term(a|1);
+			expv *= lhs;
+			break;
+
+		case '%':
+			term(a|1);
+			if(expv != 0)
+				expv = lhs/expv;
+			else{
+				if(lhs)
+					expv = 1;
+				else
+					expv = 0;
+			}
+			break;
+
+		case '&':
+			term(a|1);
+			expv &= lhs;
+			break;
+
+		case '|':
+			term(a|1);
+			expv |= lhs;
+			break;
+
+		case ')':
+			if ((a&2)==0)
+				error("unexpected `)'");
+
+		default:
+			reread();
+			return(rc);
+		}
+	}
+	return(rc);
+}
+
+int
+term(int a)
+{	/* item | monadic item | (expr) | */
+	u32int u;
+
+	switch ((int)readchar()) {
+
+	case '*':
+		term(a|1);
+		if (get4(cormap, (ADDR)expv, &u) < 0)
+			error("%r");
+		expv = u;
+		return(1);
+
+	case '@':
+		term(a|1);
+		if (get4(symmap, (ADDR)expv, &u) < 0)
+			error("%r");
+		expv = u;
+		return(1);
+
+	case '-':
+		term(a|1);
+		expv = -expv;
+		return(1);
+
+	case '~':
+		term(a|1);
+		expv = ~expv;
+		return(1);
+
+	case '(':
+		expr(2);
+		if (readchar()!=')')
+			error("syntax error: `)' expected");
+		return(1);
+
+	default:
+		reread();
+		return(item(a));
+	}
+}
+
+int
+item(int a)
+{	/* name [ . local ] | number | . | ^  | <register | 'x | | */
+	char	*base;
+	char	savc;
+	ulong u;
+	Symbol s;
+	char gsym[MAXSYM], lsym[MAXSYM];
+
+	readchar();
+	if (isfileref()) {
+		readfname(gsym);
+		rdc();			/* skip white space */
+		if (lastc == ':') {	/* it better be */
+			rdc();		/* skip white space */
+			if (!getnum(readchar))
+				error("bad number");
+			if (expv == 0)
+				expv = 1;	/* file begins at line 1 */
+			if(file2pc(gsym, expv, &u) < 0)
+				error("%r");
+			expv = u;
+			return 1;
+		}
+		error("bad file location");
+	} else if (symchar(0)) {	
+		readsym(gsym);
+		if (lastc=='.') {
+			readchar();	/* ugh */
+			if (lastc == '.') {
+				lsym[0] = '.';
+				readchar();
+				readsym(lsym+1);
+			} else if (symchar(0)) {
+				readsym(lsym);
+			} else
+				lsym[0] = 0;
+			if (localaddr(cormap, correg, gsym, lsym, &u) < 0)
+				error("%r");
+			expv = u;
+		}
+		else {
+			if (lookupsym(0, gsym, &s) < 0)
+				error("symbol not found");
+			if (s.loc.type != LADDR)
+				error("symbol not kept in memory");
+			expv = s.loc.addr;
+		}
+		reread();
+	} else if (getnum(readchar)) {
+		;
+	} else if (lastc=='.') {	
+		readchar();
+		if (!symchar(0) && lastc != '.') {
+			expv = dot;
+		} else {
+			if (findsym(locaddr(dbrget(cormap, mach->pc)), CTEXT, &s) < 0)
+				error("no current function");
+			if (lastc == '.') {
+				lsym[0] = '.';
+				readchar();
+				readsym(lsym+1);
+			} else
+				readsym(lsym);
+			if (localaddr(cormap, correg, s.name, lsym, &u) < 0)
+				error("%r");
+			expv = u;
+		}	
+		reread();
+	} else if (lastc=='"') {
+		expv=ditto;
+	} else if (lastc=='+') {
+		expv=inkdot(dotinc);
+	} else if (lastc=='^') {
+		expv=inkdot(-dotinc);
+	} else if (lastc=='<') {
+		savc=rdc();
+		base = regname(savc);
+		expv = dbrget(cormap, base);
+	}
+	else if (lastc=='\'')
+		expv = ascval();
+	else if (a)
+		error("address expected");
+	else {	
+		reread();
+		return(0);
+	}
+	return(1);
+}
+
+#define	MAXBASE	16
+
+/* service routines for expression reading */
+int
+getnum(int (*rdf)(void))
+{
+	char *cp;
+	int base, d;
+	BOOL fpnum;
+	char num[MAXLIN];
+
+	base = 0;
+	fpnum = FALSE;
+	if (lastc == '#') {
+		base = 16;
+		(*rdf)();
+	}
+	if (convdig(lastc) >= MAXBASE)
+		return (0);
+	if (lastc == '0')
+		switch ((*rdf)()) {
+		case 'x':
+		case 'X':
+			base = 16;
+			(*rdf)();
+			break;
+
+		case 't':
+		case 'T':
+			base = 10;
+			(*rdf)();
+			break;
+
+		case 'o':
+		case 'O':
+			base = 8;
+			(*rdf)();
+			break;
+		default:
+			if (base == 0)
+				base = 8;
+			break;
+		}
+	if (base == 0)
+		base = 10;
+	expv = 0;
+	for (cp = num, *cp = lastc; ;(*rdf)()) {
+		if ((d = convdig(lastc)) < base) {
+			expv *= base;
+			expv += d;
+			*cp++ = lastc;
+		}
+		else if (lastc == '.') {
+			fpnum = TRUE;
+			*cp++ = lastc;
+		} else {
+			reread();
+			break;
+		}
+	}
+	if (fpnum)
+		expv = fpin(num);
+	return (1);
+}
+
+void
+readsym(char *isymbol)
+{
+	char	*p;
+	Rune r;
+
+	p = isymbol;
+	do {
+		if (p < &isymbol[MAXSYM-UTFmax-1]){
+			r = lastc;
+			p += runetochar(p, &r);
+		}
+		readchar();
+	} while (symchar(1));
+	*p = 0;
+}
+
+void
+readfname(char *filename)
+{
+	char	*p;
+	Rune	c;
+
+	/* snarf chars until un-escaped char in terminal char set */
+	p = filename;
+	do {
+		if ((c = lastc) != '\\' && p < &filename[MAXSYM-UTFmax-1])
+			p += runetochar(p, &c);
+		readchar();
+	} while (c == '\\' || strchr(CMD_VERBS, lastc) == 0);
+	*p = 0;
+	reread();
+}
+
+int
+convdig(int c)
+{
+	if (isdigit(c))
+		return(c-'0');
+	else if (!isxdigit(c))
+		return(MAXBASE);
+	else if (isupper(c))
+		return(c-'A'+10);
+	else
+		return(c-'a'+10);
+}
+
+int
+symchar(int dig)
+{
+	if (lastc=='\\') {
+		readchar();
+		return(TRUE);
+	}
+	return(isalpha(lastc) || lastc>0x80 || lastc=='_' || dig && isdigit(lastc));
+}
+
+static long
+dbround(long a, long b)
+{
+	long w;
+
+	w = (a/b)*b;
+	if (a!=w)
+		w += b;
+	return(w);
+}
+
+ulong
+dbrget(Map *map, char *name)
+{
+	ulong u;
+
+	USED(map);
+	if(rget(correg, name, &u) < 0)
+		return ~(ulong)0;
+	return u;
+}