%%s 0/0/0 %%d D 1.1 25-Mar-82 12:03:20 v1.1 1 0 %%c Version 1.1 is the Spring 1982 Distribution of the LBL/Hughes release %%c of the Software Tools Virtual Operating System software and documentation. %%T %%I 1 #-h- cexp 272 asc 25-mar-82 07:34:27 v1.1 (sw-tools v1.1) ## common for exptoi # put on a file called 'cexp' # Used by macro and dc tools common/cexp/ top, tokst(MAXSTACK), kindst(MAXSTACK) integer top # evaluation stack pointer integer tokst # eval stack part 1: tokens integer kindst # eval stack part 2: kinds of tokens #-h- dc.r 16124 asc 25-mar-82 07:34:36 v1.1 (sw-tools v1.1) #-h- defns 605 asc 25-mar-82 07:33:20 v1.1 (sw-tools v1.1) # include ratdef define(MAXTOK,MAXLINE) define(OP,1) define(OPND,2) define(SEP,3) define(OPDONE,1) define(OPGO,2) define(OPLP,3) define(OPRP,4) define(OPOR,5) define(OPAND,6) define(OPNOT,7) define(OPEQ,8) define(OPNE,9) define(OPGT,10) define(OPGE,11) define(OPLT,12) define(OPLE,13) define(OPADD,14) define(OPSUB,15) define(OPMUL,16) define(OPDIV,17) define(OPNEG,18) define(OPMOD,19) define(OPEXP,20) define(OPPLUS,21) define(MAXOP,21) define(OPERR,-1) define(MAXSTACK,200) # evaluation stack define(MEM_SIZE,500) # size of dynamic memory in integers - needed for table #-h- main 813 asc 25-mar-82 07:33:23 v1.1 (sw-tools v1.1) ## dc - desk calculator DRIVER(dc) character name(FILENAMESIZE) integer getarg, open integer fd, i DS_DECL(Mem,MEM_SIZE) # dynamic storage call query("usage: dc [file] ...") call tbinit(MEM_SIZE) #initialize variable (hash) table fd = ERR for (i=1; getarg(i, name, FILENAMESIZE) != EOF; i=i+1) { if (name(1) == '-' & name(2) == EOS) fd = STDIN else if (name(1) != '-') { fd = open(name, READ) if (fd == ERR) call cant(name) } if (fd != ERR) { call dcexp (fd) if (fd != STDIN) call close (fd) } } if (fd == ERR) call dcexp (STDIN) DRETURN end #-h- binop 1212 asc 25-mar-82 07:33:25 v1.1 (sw-tools v1.1) ## binop - evaluates top 3 items on eval stack subroutine binop integer l, r, result, op include cexp r = tokst(top) op = tokst(top-1) l = tokst(top-2) top = top - 2 if (op == OPOR) if (l != 0 | r != 0) result = 1 else result = 0 else if (op == OPAND) if (l != 0 & r != 0) result = 1 else result = 0 else if (op == OPNOT) if (r == 0) result = 1 else result = 0 else if (op == OPEQ) if (l == r) result = 1 else result = 0 else if (op == OPNE) if (l != r) result = 1 else result = 0 else if (op == OPGT) if (l > r) result = 1 else result = 0 else if (op == OPGE) if (l >= r) result = 1 else result = 0 else if (op == OPLT) if (l < r) result = 1 else result = 0 else if (op == OPLE) if (l <= r) result = 1 else result = 0 else if (op == OPADD) result = l + r else if (op == OPSUB) result = l - r else if (op == OPNEG) result = (-r) else if (op == OPMUL) result = l * r else if (op == OPDIV) result = l / r else if (op == OPMOD) result = mod(l,r) else if (op == OPEXP) result = l**r else if (op == OPPLUS) result = (+r) tokst(top) = result return end #-h- ctonum 985 asc 25-mar-82 07:33:27 v1.1 (sw-tools v1.1) # ctonum - string to number with radix control integer function ctonum(buf,i,dradix) character buf(ARB), tmp(MAXLINE) integer ctoi integer i, j, c, n, val, radix, dradix, m string digits "0123456789abcdefABCDEF" # while (buf(i) == ' ' | buf(i) == '@t') # i = i + 1 # skip blanks if (buf(i) == '-') { i = i + 1 m = -1 } else m = 1 for (n=0;;i=i+1) { #collect digits c = index(digits,buf(i)) if (c==0) break if (c > 16) c = c-6 # convert to lower case n = n+1 tmp(n) = c-1 # save digit value } if (buf(i) == '_') { # get new radix, default radix is 10. radix = 0 i = i+1 radix = ctoi(buf,i) } else radix = dradix val = 0 for (j=1; j<=n; j = j+1) { c = tmp(j) if (c >= radix) call remark("number error") val = val * radix + c } return ( m*val ) end #-h- dcexp 2555 asc 25-mar-82 07:33:30 v1.1 (sw-tools v1.1) ## dcexp - read file and process desk calculator expressions subroutine dcexp (fd) integer fd, junk, i, answer, save integer getlin, numtoc, exptoi, index, strcmp integer ibase, obase, ubase, radexp, eqloc character line(MAXLINE), name(MAXTOK) string errmsg ": invalid expression" string ten "10" string ibname "ibase" string obname "obase" ibase = 10 obase = 10 call tbinst(ibname,ten) call tbinst(obname,ten) while(getlin(line, fd) != EOF) { radexp = 0 # assume not radix expression call strip(line) #remove blanks, tabs, NEWLINEs i = 1 save = index(line, '=') #see if result should be stored if (save != 0) { if (line(save+1) == '=') #oops, found relational save = 0 else { eqloc = save i = save + 1 line(eqloc) = EOS call scopy(line, 1, name, 1) if (strcmp(name,ibname) == 0 | strcmp(name,obname) == 0) radexp = 1 } } else { if (strcmp(line,ibname) == 0 | strcmp(line,obname) == 0) radexp = 1 } ubase = ibase if (radexp == 1) ubase = 10 answer = exptoi(line, i, ubase) if (line(i) != EOS) #error { if (save != 0) line(eqloc) = '=' call putlin(line, ERROUT) call putlin(errmsg, ERROUT) call putch('@n', ERROUT) } else { ubase = obase if (radexp == 1 | save != 0) ubase = 10 junk = numtoc(answer, line, MAXLINE, ubase) if (save != 0) #store answer { call tbinst(name, line) if (strcmp(ibname,name) == 0) ibase = answer if (strcmp(obname,name) == 0) obase = answer } else { call putlin(line, STDOUT) call putch('@n', STDOUT) } } } return end #-h- exptoi 3618 asc 25-mar-82 07:33:36 v1.1 (sw-tools v1.1) ## exptoi - evalutate arithmetic expression integer function exptoi (exp, ptr, radix) integer exptok, stackx character exp(ARB) integer ptr, radix integer k, tok, kind, preced(MAXOP) include cexp # precedence of respective operators data preced(1), preced(2), preced(3), preced(4), preced(5), preced(6), preced(7), preced(8), preced(9), preced(10), preced(11), preced(12), preced(13), preced(14), preced(15), preced(16), preced(17), preced(18), preced(19), preced(20), preced(21) / 0, 0, # EOS, start_expr 1, 1, # ( ) 2, 2, # | & 3, # ! (or ^ or ~) 4,4,4,4,4,4, # == != > >= < <= 5, 5, # + - 6, 6, # * / 8, 6, 7, 8 /# neg, mod, expon, plus k = ptr top = 1 tokst(top) = OPGO kindst(top) = SEP while (exptok(exp, k, tok, kind, radix) == YES) #loop thru legal toks { if (kind == OPND) { if (kindst(top) == OPND) return(0) } else if (kind == OP) { if (kindst(top) == OP) return(0) else if (kindst(top) == SEP) { #check for unary +,- or ! if (tok != OPADD & tok != OPSUB & tok != OPNOT) return(0) if (stackx(0, OPND) == ERR) return(0) if (tok == OPADD) tok = OPPLUS else if (tok == OPSUB) tok = OPNEG } else #kindst(top) == OPND { if (kindst(top-1) == OP) { while(preced(tokst(top-1)) >= preced(tok)) call binop } } } else # (kind == SEP) { if (tok != OPLP) #if tok == ( or tok == EOS { if (kindst(top) != OPND) return(0) while(preced(tokst(top-1)) > preced(tok)) { if (kindst(top-1) == OP) call binop else return(0) # no right paren } if (preced(tokst(top-1)) == preced(tok)) { if (tok == OPDONE) { ptr = k #normal return return(tokst(top)) } else #remove matching '(' { tok = tokst(top) kind = kindst(top) top = top -2 } } else #unbalanced parens return(0) } } # stack new tok, kind if (stackx(tok, kind) == ERR) return(0) } return(0) end #-h- exptok 3773 asc 25-mar-82 07:33:42 v1.1 (sw-tools v1.1) ## exptok - get expression token for evaluation integer function exptok(exp, k, tok, kind, radix) character exp(ARB), defn(MAXTOK), name(MAXTOK) integer k #index, updated unless EOS integer tok #return value, token found integer kind #return value, kind of token integer radix #default radix for numbers integer ctonum, tblook character type character c, cn include cexp string digits "0123456789abcdefABCDEF" c = type(exp(k)) if (radix > 10) { if (index(digits,exp(k)) > 0) c = DIGIT } if (c == DIGIT) { tok = ctonum(exp, k, radix) kind = OPND return(YES) } else if (c == LETTER) { #found stored variable name call movnam(exp, k, name, 1) k = k + length(name) if (tblook(name, defn) == YES) { i = 1 tok = ctonum(defn, i, 10) kind = OPND return(YES) } else return(NO) } else #c is symbol { cn = exp(k+1) kind = OP if (c == '~') if (cn == '=') { tok = OPNE k = k + 1 } else tok = OPNOT else if (c == '^') if (cn == '=') { tok = OPNE k = k + 1 } else tok = OPNOT else if (c == '!') if (cn == '=') { tok = OPNE k = k + 1 } else tok = OPNOT else if (c == '<') if (cn == '=') { tok = OPLE k = k + 1 } else tok = OPLT else if (c == '>') if (cn == '=') { tok = OPGE k = k + 1 } else tok = OPGT else if (c == '=') if (cn == '=') { tok = OPEQ k = k + 1 } else tok = OPERR else if (c == '|') tok = OPOR else if (c == '&') tok = OPAND else if (c == '+') tok = OPADD else if (c == '-') tok = OPSUB else if (c == '*') if (cn == '*') { tok = OPEXP k = k + 1 } else tok = OPMUL else if (c == '/') tok = OPDIV else if (c == '%') tok = OPMOD else if (c == '(') { kind = SEP tok = OPLP } else if (c == ')') { kind = SEP tok = OPRP } else if (c == EOS) { kind = SEP tok = OPDONE } else tok = OPERR if (tok == OPERR) return(NO) if (tok != OPDONE) k = k + 1 return(YES) } end #-h- movnam 372 asc 25-mar-82 07:33:46 v1.1 (sw-tools v1.1) ## movnam - move in(i) to out(j) until non-alphanumeric found subroutine movnam (in, i, out, j) character in(ARB), out(ARB) integer i, j, k1, k2 character type character c k1 = i k2 = j for(c=type(in(k1)); c == LETTER | c == DIGIT; c=type(in(k1))) { out(k2) = in(k1) k1 = k1 + 1 k2 = k2 + 1 } out(k2) = EOS return end #-h- numtoc 735 asc 25-mar-82 07:33:48 v1.1 (sw-tools v1.1) ## numtoc - convert integer int to char string in str integer function numtoc(int, str, size, radix) integer mod integer radix integer d, i, int, intval, j, k, size character str(ARB) string digits "0123456789ABCDEF" intval = abs(int) str(1) = EOS i = 1 repeat { # generate digits i = i+1 d = mod(intval,radix) str(i) = digits(d+1) intval = intval / radix } until (intval == 0 | i >= size) if (int < 0 & i < size) { # then sign i = i+1 str(i) = '-' } numtoc = i - 1 for (j = 1; j < i; j = j+1) { # reverse digits k = str(i) str(i) = str(j) str(j) = k i = i-1 } return end #-h- stackx 322 asc 25-mar-82 07:33:50 v1.1 (sw-tools v1.1) ## stackx - put next expression on arith evaluation stack integer function stackx(tok, kind) integer tok, kind include cexp if (top >= MAXSTACK) { call remark ("arith evaluation stack overflow.") return (ERR) } top = top + 1 tokst(top) = tok kindst(top) = kind return(OK) end #-h- strip 331 asc 25-mar-82 07:33:52 v1.1 (sw-tools v1.1) ## strip - string blanks, tabs, and NEWLINES from line subroutine strip (line) character line(ARB) integer i for (i=1; line(i) != EOS; ) { if (line(i) == ' ' | line(i) == '@t' | line(i) == '@n') call scopy(line, i+1, line, i) else i = i + 1 } return end #-h- dc.fmt 3590 asc 25-mar-82 07:34:51 v1.1 (sw-tools v1.1) .so ~bin/manhdr .hd Dc (1) 20-Jul-80 desk calculator .sy dc [file] ... .ds dc evaluates integer expressions from the source files, one expression per input line. If no input files are given, or the filename '-' is specified, dc reads from the standard input. Ordinarily dc operates on decimal integer arithmetic expressions, but the user may specify an input base and output base other than decimal. Expressions may be simple arithmetic expressions or replacement expressions. The values of simple expressions are written on standard output when they are evaluated. Replacement expressions are used to hold temporary values, and are not automatically printed. A simple expression is a normal arithmetic expression using numbers, variables, parentheses, and the following operators, listed in order of precedence: .in +5 .nf + - unary plus and negation operators. These may only appear at the start of a simple expression or after a "(" ** exponentiation * / % multiply, divide, modulo (remainder) + - add, subtract == != relations - equals, not equal to, > >= greater than, greater than or equal to, < <= less than, less than or equal to (!=, ^=, ~= all treated as "not equal") ! unary logical not (also ~ and ^) | & logical or, and .in -5 .fi The logical operators ! | & and the relational operators result in the values 1 for true and 0 for false. A replacement expression is: .sp .ce name = simple expression .sp where 'name' is a character string of (virtually) any length, starting with a letter and consisting of only letters and digits. (The characters a-f should not be considered letters when operating in hexadecimal mode.) Variables are automatically declared when they first appear to the left of an "=" sign, and they should not be used in a simple expression until they have been declared. Radix Control .br .in +5 Radix control is available in 2 ways: .br 1) There are default radix values for both input and output which may be changed by setting the predefined variables 'ibase' (input base) and 'obase' (output base). (Radix 10 is always used to evaluate and/or print radix-defining expressions.) For example, .sp .in +10 ibase = 2 .br obase = 16 .in -10 .sp would accept input in binary and print results in hexadecimal. 2) The radix of individual numbers may be explicitly given by following the number with an underscore character and then the desired radix. For example, .sp .ce 100_16 .sp would specify the hex number 100 (256 in decimal). .in -5 .ex .ti +15 10 + (-64 / 2**4) .br would print the answer "6" .sp .in +15 .nf temp = 101_2 temp == 5 .fi .in -15 would print the answer "1" (true) .nf .in +15 ibase = 16 obase = 2 1a + f .in -15 .fi would print the answer "101001" .sp .in +15 .nf ibase = 16 numa = 100_10 numb = 100 numa + numb .in -15 .fi would print the answer "356" .sp 1 .fl none .sa macro, the UNIX M4 macro package .br The UNIX tools dc and bc .di .in +3 .ti -3 arith evaluation stack overflow .br arithmetic expressions have been nested too deeply. The size of the stack is set by the MAXSTACK definition in the source code. .ti -3 number error .br an input number has a number/character bigger than the current radix .sp .ti -3 expression error .br invalid arithmetic expression .in -3 .au Philip H. Scherrer (Stanford U.) .bu dc only works with integers The maximum value allowed depends on the host machine and is the largest Fortran integer %%E 1