aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/db/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/db/expr.c')
-rw-r--r--src/cmd/db/expr.c397
1 files changed, 397 insertions, 0 deletions
diff --git a/src/cmd/db/expr.c b/src/cmd/db/expr.c
new file mode 100644
index 00000000..8d33e7f4
--- /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;
+}