[Midnightbsd-cvs] src: src/usr.bin: Replacing the GNU bc/dc with BSD versions obtained

archite at midnightbsd.org archite at midnightbsd.org
Sat Aug 25 14:43:24 EDT 2007


Log Message:
-----------
Replacing the GNU bc/dc with BSD versions obtained from OpenBSD.

Modified Files:
--------------
    src/usr.bin:
        Makefile (r1.10 -> r1.11)

Added Files:
-----------
    src/usr.bin/bc:
        Makefile (r1.1)
        bc.1 (r1.1)
        bc.library (r1.1)
        bc.y (r1.1)
        extern.h (r1.1)
        pathnames.h (r1.1)
        scan.l (r1.1)
    src/usr.bin/bc/USD.doc:
        Makefile (r1.1)
        bc (r1.1)
    src/usr.bin/dc:
        Makefile (r1.1)
        bcode.c (r1.1)
        bcode.h (r1.1)
        dc.1 (r1.1)
        dc.c (r1.1)
        extern.h (r1.1)
        inout.c (r1.1)
        mem.c (r1.1)
        stack.c (r1.1)
    src/usr.bin/dc/USD.doc:
        Makefile (r1.1)
        dc (r1.1)

-------------- next part --------------
--- /dev/null
+++ usr.bin/bc/extern.h
@@ -0,0 +1,40 @@
+/*      $OpenBSD: extern.h,v 1.6 2006/03/18 20:44:43 otto Exp $	*/
+/*	$MidnightBSD: src/usr.bin/bc/extern.h,v 1.1 2007/08/25 18:43:20 archite Exp $
+
+/*
+ * Copyright (c) 2003, Otto Moerbeek <otto at drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+
+struct lvalue {
+	ssize_t load;
+	ssize_t store;
+};
+
+int		yylex(void);
+void		yyerror(char *);
+void		fatal(const char *);
+void		abort_line(int);
+
+extern int	lineno;
+extern char	*yytext;
+extern FILE	*yyin;
+extern int	fileindex;
+extern int	sargc;
+extern char	**sargv;
+extern char	*filename;
+extern char	*cmdexpr;
+bool		interactive;
--- /dev/null
+++ usr.bin/bc/scan.l
@@ -0,0 +1,288 @@
+%{
+/*      $OpenBSD: scan.l,v 1.21 2006/03/18 20:44:43 otto Exp $	*/
+/*	$MidnightBSD: src/usr.bin/bc/scan.l,v 1.1 2007/08/25 18:43:20 archite Exp $ */
+
+/*
+ * Copyright (c) 2003, Otto Moerbeek <otto at drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$MidnightBSD: src/usr.bin/bc/scan.l,v 1.1 2007/08/25 18:43:20 archite Exp $";
+#endif /* not lint */
+
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+#include "pathnames.h"
+#include "bc.h"
+
+int		lineno;
+bool		interactive;
+
+static char	*strbuf = NULL;
+static size_t	strbuf_sz = 1;
+static bool	dot_seen;
+
+static void	init_strbuf(void);
+static void	add_str(const char *);
+
+%}
+
+%option always-interactive
+
+DIGIT		[0-9A-F]
+ALPHA		[a-z_]
+ALPHANUM	[a-z_0-9]
+
+%x		comment string number
+
+%%
+
+"/*"		BEGIN(comment);
+<comment>{
+	"*/"	BEGIN(INITIAL);
+	\n	lineno++;
+	\*	;
+	[^*\n]+	;
+	<<EOF>>	fatal("end of file in comment");
+}
+
+\"		BEGIN(string); init_strbuf();
+<string>{
+	[^"\n\\\[\]]+	add_str(yytext);
+	\[	add_str("\\[");
+	\]	add_str("\\]");
+	\\	add_str("\\\\");
+	\n	add_str("\n"); lineno++;
+	\"	BEGIN(INITIAL); yylval.str = strbuf; return STRING;
+	<<EOF>>	fatal("end of file in string");
+}
+
+{DIGIT}+	{
+			BEGIN(number);
+			dot_seen = false;
+			init_strbuf();
+			add_str(yytext);
+		}
+\.		{
+			BEGIN(number);
+			dot_seen = true;
+			init_strbuf();
+			add_str(".");
+		}
+<number>{
+	{DIGIT}+	add_str(yytext);
+	\.	{
+			if (dot_seen) {
+				BEGIN(INITIAL);
+				yylval.str = strbuf;
+				unput('.');
+				return NUMBER;
+			} else {
+				dot_seen = true;
+				add_str(".");
+			}
+		}
+	\\\n[ \t]*	lineno++;
+	[^0-9A-F\.]	{
+			BEGIN(INITIAL);
+			unput(yytext[0]);
+			if (strcmp(strbuf, ".") == 0)
+				return DOT;
+			else {
+				yylval.str = strbuf;
+				return NUMBER;
+			}
+		}
+}
+
+"auto"		return AUTO;
+"break"		return BREAK;
+"continue"	return CONTINUE;
+"define"	return DEFINE;
+"else"		return ELSE;
+"ibase"		return IBASE;
+"if"		return IF;
+"last"		return DOT;
+"for"		return FOR;
+"length"	return LENGTH;
+"obase"		return OBASE;
+"print"		return PRINT;
+"quit"		return QUIT;
+"return"	return RETURN;
+"scale"		return SCALE;
+"sqrt"		return SQRT;
+"while"		return WHILE;
+
+"^"		return EXPONENT;
+"*"		return MULTIPLY;
+"/"		return DIVIDE;
+"%"		return REMAINDER;
+
+"!"		return BOOL_NOT;
+"&&"		return BOOL_AND;
+"||"		return BOOL_OR;
+
+"+"		return PLUS;
+"-"		return MINUS;
+
+"++"		return INCR;
+"--"		return DECR;
+
+"="		yylval.str = ""; return ASSIGN_OP;
+"+="		yylval.str = "+"; return ASSIGN_OP;
+"-="		yylval.str = "-"; return ASSIGN_OP;
+"*="		yylval.str = "*"; return ASSIGN_OP;
+"/="		yylval.str = "/"; return ASSIGN_OP;
+"%="		yylval.str = "%"; return ASSIGN_OP;
+"^="		yylval.str = "^"; return ASSIGN_OP;
+
+"=="		return EQUALS;
+"<="		return LESS_EQ;
+">="		return GREATER_EQ;
+"!="		return UNEQUALS;
+"<"		return LESS;
+">"		return GREATER;
+
+","		return COMMA;
+";"		return SEMICOLON;
+
+"("		return LPAR;
+")"		return RPAR;
+
+"["		return LBRACKET;
+"]"		return RBRACKET;
+
+"{"		return LBRACE;
+"}"		return RBRACE;
+
+{ALPHA}{ALPHANUM}* {
+			/* alloc an extra byte for the type marker */
+			char *p = malloc(yyleng + 2);
+			if (p == NULL)
+				err(1, NULL);
+			strlcpy(p, yytext, yyleng + 1);
+			yylval.astr = p;
+			return LETTER;
+		}
+
+\\\n		lineno++;
+\n		lineno++; return NEWLINE;
+
+#[^\n]*		;
+[ \t]		;
+<<EOF>>		return QUIT;
+.		yyerror("illegal character");
+
+%%
+
+static void
+init_strbuf(void)
+{
+	if (strbuf == NULL) {
+		strbuf = malloc(strbuf_sz);
+		if (strbuf == NULL)
+			err(1, NULL);
+	}
+	strbuf[0] = '\0';
+}
+
+static void
+add_str(const char *str)
+{
+	size_t arglen;
+
+	arglen = strlen(str);
+
+	if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
+		size_t newsize;
+		char *p;
+
+		newsize = strbuf_sz + arglen + 1;
+		p = realloc(strbuf, newsize);
+		if (p == NULL) {
+			free(strbuf);
+			err(1, NULL);
+		}
+		strbuf_sz = newsize;
+		strbuf = p;
+	}
+	strlcat(strbuf, str, strbuf_sz);
+}
+
+/* ARGSUSED */
+void
+abort_line(int sig)
+{
+	const char str[] = "[\n]P\n";
+	int save_errno;
+
+	save_errno = errno;
+	YY_FLUSH_BUFFER;	/* XXX signal race? */
+	write(STDOUT_FILENO, str, sizeof(str) - 1);
+	errno = save_errno;
+}
+
+int
+yywrap(void)
+{
+	static int state;
+	static YY_BUFFER_STATE buf;
+
+	if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
+		filename = sargv[fileindex++];
+		yyin = fopen(filename, "r");
+		lineno = 1;
+		if (yyin == NULL)
+			err(1, "cannot open %s", filename);
+		return (0);
+	}
+	if (state == 0 && cmdexpr[0] != '\0') {
+		buf = yy_scan_string(cmdexpr);
+		state++;
+		lineno = 1;
+		filename = "command line";
+		return (0);
+	} else if (state == 1) {
+		yy_delete_buffer(buf);
+		free(cmdexpr);
+		state++;
+	}
+	if (yyin != NULL && yyin != stdin)
+		fclose(yyin);
+	if (fileindex < sargc) {
+		filename = sargv[fileindex++];
+		yyin = fopen(filename, "r");
+		lineno = 1;
+		if (yyin == NULL)
+			err(1, "cannot open %s", filename);
+		return (0);
+	} else if (fileindex == sargc) {
+		fileindex++;
+		yyin = stdin;
+		if (interactive)
+			signal(SIGINT, abort_line);
+		lineno = 1;
+		filename = "stdin";
+		return (0);
+	}
+	return (1);
+}
+
--- /dev/null
+++ usr.bin/bc/bc.y
@@ -0,0 +1,1148 @@
+%{
+/*	$OpenBSD: bc.y,v 1.32 2006/05/18 05:49:53 otto Exp $	*/
+/*	$MidnightBSD: src/usr.bin/bc/bc.y,v 1.1 2007/08/25 18:43:20 archite Exp $ */
+
+/*
+ * Copyright (c) 2003, Otto Moerbeek <otto at drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This implementation of bc(1) uses concepts from the original 4.4
+ * BSD bc(1). The code itself is a complete rewrite, based on the
+ * Posix defined bc(1) grammar. Other differences include type safe
+ * usage of pointers to build the tree of emitted code, typed yacc
+ * rule values, dynamic allocation of all data structures and a
+ * completely rewritten lexical analyzer using lex(1).
+ *
+ * Some effort has been made to make sure that the generated code is
+ * the same as the code generated by the older version, to provide
+ * easy regression testing.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$MidnightBSD: src/usr.bin/bc/bc.y,v 1.1 2007/08/25 18:43:20 archite Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <search.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+#include "pathnames.h"
+
+#define END_NODE	((ssize_t) -1)
+#define CONST_STRING	((ssize_t) -2)
+#define ALLOC_STRING	((ssize_t) -3)
+
+struct tree {
+	ssize_t			index;
+	union {
+		char		*astr;
+		const char	*cstr;
+	} u;
+};
+
+int			yyparse(void);
+int			yywrap(void);
+
+int			fileindex;
+int			sargc;
+char			**sargv;
+char			*filename;
+char			*cmdexpr;
+
+static void		grow(void);
+static ssize_t		cs(const char *);
+static ssize_t		as(const char *);
+static ssize_t		node(ssize_t, ...);
+static void		emit(ssize_t);
+static void		emit_macro(int, ssize_t);
+static void		free_tree(void);
+static ssize_t		numnode(int);
+static ssize_t		lookup(char *, size_t, char);
+static ssize_t		letter_node(char *);
+static ssize_t		array_node(char *);
+static ssize_t		function_node(char *);
+
+static void		add_par(ssize_t);
+static void		add_local(ssize_t);
+static void		warning(const char *);
+static void		init(void);
+static __dead2 void	usage(void);
+static char		*escape(const char *);
+
+static ssize_t		instr_sz = 0;
+static struct tree	*instructions = NULL;
+static ssize_t		current = 0;
+static int		macro_char = '0';
+static int		reset_macro_char = '0';
+static int		nesting = 0;
+static int		breakstack[16];
+static int		breaksp = 0;
+static ssize_t		prologue;
+static ssize_t		epilogue;
+static bool		st_has_continue;
+static char		str_table[UCHAR_MAX][2];
+static bool		do_fork = true;
+static u_short		var_count;
+static pid_t		dc;
+
+extern char *__progname;
+
+#define BREAKSTACK_SZ	(sizeof(breakstack)/sizeof(breakstack[0]))
+
+/* These values are 4.4BSD bc compatible */
+#define FUNC_CHAR	0x01
+#define ARRAY_CHAR	0xa1
+
+/* Skip '\0', [, \ and ] */
+#define ENCODE(c)	((c) < '[' ? (c) : (c) + 3);
+#define VAR_BASE	(256-4)
+#define MAX_VARIABLES	(VAR_BASE * VAR_BASE)
+
+%}
+
+%start program
+
+%union {
+	ssize_t		node;
+	struct lvalue	lvalue;
+	const char	*str;
+	char		*astr;
+}
+
+%token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT
+%token NEWLINE
+%token <astr> LETTER
+%token <str> NUMBER STRING
+%token DEFINE BREAK QUIT LENGTH
+%token RETURN FOR IF WHILE SQRT
+%token SCALE IBASE OBASE AUTO
+%token CONTINUE ELSE PRINT
+
+%left BOOL_OR
+%left BOOL_AND
+%nonassoc BOOL_NOT
+%nonassoc EQUALS LESS_EQ GREATER_EQ UNEQUALS LESS GREATER
+%right <str> ASSIGN_OP
+%left PLUS MINUS
+%left MULTIPLY DIVIDE REMAINDER
+%right EXPONENT
+%nonassoc UMINUS
+%nonassoc INCR DECR
+
+%type <lvalue>	named_expression
+%type <node>	argument_list
+%type <node>	alloc_macro
+%type <node>	expression
+%type <node>	function
+%type <node>	function_header
+%type <node>	input_item
+%type <node>	opt_argument_list
+%type <node>	opt_expression
+%type <node>	opt_relational_expression
+%type <node>	opt_statement
+%type <node>	print_expression
+%type <node>	print_expression_list
+%type <node>	relational_expression
+%type <node>	return_expression
+%type <node>	semicolon_list
+%type <node>	statement
+%type <node>	statement_list
+
+%%
+
+program		: /* empty */
+		| program input_item
+		;
+
+input_item	: semicolon_list NEWLINE
+			{
+				emit($1);
+				macro_char = reset_macro_char;
+				putchar('\n');
+				free_tree();
+				st_has_continue = false;
+			}
+		| function
+			{
+				putchar('\n');
+				free_tree();
+				st_has_continue = false;
+			}
+		| error NEWLINE
+			{
+				yyerrok;
+			}
+		| error QUIT
+			{
+				yyerrok;
+			}
+		;
+
+semicolon_list	: /* empty */
+			{
+				$$ = cs("");
+			}
+		| statement
+		| semicolon_list SEMICOLON statement
+			{
+				$$ = node($1, $3, END_NODE);
+			}
+		| semicolon_list SEMICOLON
+		;
+
+statement_list	: /* empty */
+			{
+				$$ = cs("");
+			}
+		| statement
+		| statement_list NEWLINE
+		| statement_list NEWLINE statement
+			{
+				$$ = node($1, $3, END_NODE);
+			}
+		| statement_list SEMICOLON
+		| statement_list SEMICOLON statement
+			{
+				$$ = node($1, $3, END_NODE);
+			}
+		;
+
+
+opt_statement	: /* empty */
+			{
+				$$ = cs("");
+			}
+		| statement
+		;
+
+statement	: expression
+			{
+				$$ = node($1, cs("ps."), END_NODE);
+			}
+		| named_expression ASSIGN_OP expression
+			{
+				if ($2[0] == '\0')
+					$$ = node($3, cs($2), $1.store,
+					    END_NODE);
+				else
+					$$ = node($1.load, $3, cs($2), $1.store,
+					    END_NODE);
+			}
+		| STRING
+			{
+				$$ = node(cs("["), as($1),
+				    cs("]P"), END_NODE);
+			}
+		| BREAK
+			{
+				if (breaksp == 0) {
+					warning("break not in for or while");
+					YYERROR;
+				} else {
+					$$ = node(
+					    numnode(nesting -
+						breakstack[breaksp-1]),
+					    cs("Q"), END_NODE);
+				}
+			}
+		| CONTINUE
+			{
+				if (breaksp == 0) {
+					warning("continue not in for or while");
+					YYERROR;
+				} else {
+					st_has_continue = true;
+					$$ = node(numnode(nesting -
+					    breakstack[breaksp-1] - 1),
+					    cs("J"), END_NODE);
+				}
+			}
+		| QUIT
+			{
+				sigset_t mask;
+
+				putchar('q');
+				fflush(stdout);
+				if (dc) {
+					sigprocmask(SIG_BLOCK, NULL, &mask);
+					sigsuspend(&mask);
+				} else
+					exit(0);
+			}
+		| RETURN return_expression
+			{
+				if (nesting == 0) {
+					warning("return must be in a function");
+					YYERROR;
+				}
+				$$ = $2;
+			}
+		| FOR LPAR alloc_macro opt_expression SEMICOLON
+		     opt_relational_expression SEMICOLON
+		     opt_expression RPAR opt_statement pop_nesting
+			{
+				ssize_t n;
+
+				if (st_has_continue)
+					n = node($10, cs("M"), $8, cs("s."),
+					    $6, $3, END_NODE);
+				else
+					n = node($10, $8, cs("s."), $6, $3,
+					    END_NODE);
+
+				emit_macro($3, n);
+				$$ = node($4, cs("s."), $6, $3, cs(" "),
+				    END_NODE);
+			}
+		| IF LPAR alloc_macro pop_nesting relational_expression RPAR
+		      opt_statement
+			{
+				emit_macro($3, $7);
+				$$ = node($5, $3, cs(" "), END_NODE);
+			}
+		| IF LPAR alloc_macro pop_nesting relational_expression RPAR
+		      opt_statement ELSE alloc_macro pop_nesting opt_statement
+			{
+				emit_macro($3, $7);
+				emit_macro($9, $11);
+				$$ = node($5, $3, cs("e"), $9, cs(" "),
+				    END_NODE);
+			}
+		| WHILE LPAR alloc_macro relational_expression RPAR
+		      opt_statement pop_nesting
+			{
+				ssize_t n;
+
+				if (st_has_continue)
+					n = node($6, cs("M"), $4, $3, END_NODE);
+				else
+					n = node($6, $4, $3, END_NODE);
+				emit_macro($3, n);
+				$$ = node($4, $3, cs(" "), END_NODE);
+			}
+		| LBRACE statement_list RBRACE
+			{
+				$$ = $2;
+			}
+		| PRINT print_expression_list
+			{
+				$$ = $2;
+			}
+		;
+
+alloc_macro	: /* empty */
+			{
+				$$ = cs(str_table[macro_char]);
+				macro_char++;
+				/* Do not use [, \ and ] */
+				if (macro_char == '[')
+					macro_char += 3;
+				/* skip letters */
+				else if (macro_char == 'a')
+					macro_char = '{';
+				else if (macro_char == ARRAY_CHAR)
+					macro_char += 26;
+				else if (macro_char == 255)
+					fatal("program too big");
+				if (breaksp == BREAKSTACK_SZ)
+					fatal("nesting too deep");
+				breakstack[breaksp++] = nesting++;
+			}
+		;
+
+pop_nesting	: /* empty */
+			{
+				breaksp--;
+			}
+		;
+
+function	: function_header opt_parameter_list RPAR opt_newline
+		  LBRACE NEWLINE opt_auto_define_list
+		  statement_list RBRACE
+			{
+				int n = node(prologue, $8, epilogue,
+				    cs("0"), numnode(nesting),
+				    cs("Q"), END_NODE);
+				emit_macro($1, n);
+				reset_macro_char = macro_char;
+				nesting = 0;
+				breaksp = 0;
+			}
+		;
+
+function_header : DEFINE LETTER LPAR
+			{
+				$$ = function_node($2);
+				free($2);
+				prologue = cs("");
+				epilogue = cs("");
+				nesting = 1;
+				breaksp = 0;
+				breakstack[breaksp] = 0;
+			}
+		;
+
+opt_newline	: /* empty */
+		| NEWLINE
+		;
+
+opt_parameter_list
+		: /* empty */
+		| parameter_list
+		;
+
+
+parameter_list	: LETTER
+			{
+				add_par(letter_node($1));
+				free($1);
+			}
+		| LETTER LBRACKET RBRACKET
+			{
+				add_par(array_node($1));
+				free($1);
+			}
+		| parameter_list COMMA LETTER
+			{
+				add_par(letter_node($3));
+				free($3);
+			}
+		| parameter_list COMMA LETTER LBRACKET RBRACKET
+			{
+				add_par(array_node($3));
+				free($3);
+			}
+		;
+
+
+
+opt_auto_define_list
+		: /* empty */
+		| AUTO define_list NEWLINE
+		| AUTO define_list SEMICOLON
+		;
+
+
+define_list	: LETTER
+			{
+				add_local(letter_node($1));
+				free($1);
+			}
+		| LETTER LBRACKET RBRACKET
+			{
+				add_local(array_node($1));
+				free($1);
+			}
+		| define_list COMMA LETTER
+			{
+				add_local(letter_node($3));
+				free($3);
+			}
+		| define_list COMMA LETTER LBRACKET RBRACKET
+			{
+				add_local(array_node($3));
+				free($3);
+			}
+		;
+
+
+opt_argument_list
+		: /* empty */
+			{
+				$$ = cs("");
+			}
+		| argument_list
+		;
+
+
+argument_list	: expression
+		| argument_list COMMA expression
+			{
+				$$ = node($1, $3, END_NODE);
+			}
+		| argument_list COMMA LETTER LBRACKET RBRACKET
+			{
+				$$ = node($1, cs("l"), array_node($3),
+				    END_NODE);
+				free($3);
+			}
+		;
+
+opt_relational_expression
+		: /* empty */
+			{
+				$$ = cs(" 0 0=");
+			}
+		| relational_expression
+		;
+
+relational_expression
+		: expression EQUALS expression
+			{
+				$$ = node($1, $3, cs("="), END_NODE);
+			}
+		| expression UNEQUALS expression
+			{
+				$$ = node($1, $3, cs("!="), END_NODE);
+			}
+		| expression LESS expression
+			{
+				$$ = node($1, $3, cs(">"), END_NODE);
+			}
+		| expression LESS_EQ expression
+			{
+				$$ = node($1, $3, cs("!<"), END_NODE);
+			}
+		| expression GREATER expression
+			{
+				$$ = node($1, $3, cs("<"), END_NODE);
+			}
+		| expression GREATER_EQ expression
+			{
+				$$ = node($1, $3, cs("!>"), END_NODE);
+			}
+		| expression
+			{
+				$$ = node($1, cs(" 0!="), END_NODE);
+			}
+		;
+
+
+return_expression
+		: /* empty */
+			{
+				$$ = node(cs("0"), epilogue,
+				    numnode(nesting), cs("Q"), END_NODE);
+			}
+		| expression
+			{
+				$$ = node($1, epilogue,
+				    numnode(nesting), cs("Q"), END_NODE);
+			}
+		| LPAR RPAR
+			{
+				$$ = node(cs("0"), epilogue,
+				    numnode(nesting), cs("Q"), END_NODE);
+			}
+		;
+
+
+opt_expression : /* empty */
+			{
+				$$ = cs(" 0");
+			}
+		| expression
+		;
+
+expression	: named_expression
+			{
+				$$ = node($1.load, END_NODE);
+			}
+		| DOT	{
+				$$ = node(cs("l."), END_NODE);
+			}
+		| NUMBER
+			{
+				$$ = node(cs(" "), as($1), END_NODE);
+			}
+		| LPAR expression RPAR
+			{
+				$$ = $2;
+			}
+		| LETTER LPAR opt_argument_list RPAR
+			{
+				$$ = node($3, cs("l"),
+				    function_node($1), cs("x"),
+				    END_NODE);
+				free($1);
+			}
+		| MINUS expression %prec UMINUS
+			{
+				$$ = node(cs(" 0"), $2, cs("-"),
+				    END_NODE);
+			}
+		| expression PLUS expression
+			{
+				$$ = node($1, $3, cs("+"), END_NODE);
+			}
+		| expression MINUS expression
+			{
+				$$ = node($1, $3, cs("-"), END_NODE);
+			}
+		| expression MULTIPLY expression
+			{
+				$$ = node($1, $3, cs("*"), END_NODE);
+			}
+		| expression DIVIDE expression
+			{
+				$$ = node($1, $3, cs("/"), END_NODE);
+			}
+		| expression REMAINDER expression
+			{
+				$$ = node($1, $3, cs("%"), END_NODE);
+			}
+		| expression EXPONENT expression
+			{
+				$$ = node($1, $3, cs("^"), END_NODE);
+			}
+		| INCR named_expression
+			{
+				$$ = node($2.load, cs("1+d"), $2.store,
+				    END_NODE);
+			}
+		| DECR named_expression
+			{
+				$$ = node($2.load, cs("1-d"),
+				    $2.store, END_NODE);
+			}
+		| named_expression INCR
+			{
+				$$ = node($1.load, cs("d1+"),
+				    $1.store, END_NODE);
+			}
+		| named_expression DECR
+			{
+				$$ = node($1.load, cs("d1-"),
+				    $1.store, END_NODE);
+			}
+		| named_expression ASSIGN_OP expression
+			{
+				if ($2[0] == '\0')
+					$$ = node($3, cs($2), cs("d"), $1.store,
+					    END_NODE);
+				else
+					$$ = node($1.load, $3, cs($2), cs("d"),
+					    $1.store, END_NODE);
+			}
+		| LENGTH LPAR expression RPAR
+			{
+				$$ = node($3, cs("Z"), END_NODE);
+			}
+		| SQRT LPAR expression RPAR
+			{
+				$$ = node($3, cs("v"), END_NODE);
+			}
+		| SCALE LPAR expression RPAR
+			{
+				$$ = node($3, cs("X"), END_NODE);
+			}
+		| BOOL_NOT expression
+			{
+				$$ = node($2, cs("N"), END_NODE);
+			}
+		| expression BOOL_AND alloc_macro pop_nesting expression
+			{
+				ssize_t n = node(cs("R"), $5, END_NODE);
+				emit_macro($3, n);
+				$$ = node($1, cs("d0!="), $3, END_NODE);
+			}
+		| expression BOOL_OR alloc_macro pop_nesting expression
+			{
+				ssize_t n = node(cs("R"), $5, END_NODE);
+				emit_macro($3, n);
+				$$ = node($1, cs("d0="), $3, END_NODE);
+			}
+		| expression EQUALS expression
+			{
+				$$ = node($1, $3, cs("G"), END_NODE);
+			}
+		| expression UNEQUALS expression
+			{
+				$$ = node($1, $3, cs("GN"), END_NODE);
+			}
+		| expression LESS expression
+			{
+				$$ = node($3, $1, cs("("), END_NODE);
+			}
+		| expression LESS_EQ expression
+			{
+				$$ = node($3, $1, cs("{"), END_NODE);
+			}
+		| expression GREATER expression
+			{
+				$$ = node($1, $3, cs("("), END_NODE);
+			}
+		| expression GREATER_EQ expression
+			{
+				$$ = node($1, $3, cs("{"), END_NODE);
+			}
+		;
+
+named_expression
+		: LETTER
+			{
+				$$.load = node(cs("l"), letter_node($1),
+				    END_NODE);
+				$$.store = node(cs("s"), letter_node($1),
+				    END_NODE);
+				free($1);
+			}
+		| LETTER LBRACKET expression RBRACKET
+			{
+				$$.load = node($3, cs(";"),
+				    array_node($1), END_NODE);
+				$$.store = node($3, cs(":"),
+				    array_node($1), END_NODE);
+				free($1);
+			}
+		| SCALE
+			{
+				$$.load = cs("K");
+				$$.store = cs("k");
+			}
+		| IBASE
+			{
+				$$.load = cs("I");
+				$$.store = cs("i");
+			}
+		| OBASE
+			{
+				$$.load = cs("O");
+				$$.store = cs("o");
+			}
+		;
+
+print_expression_list
+		: print_expression
+		| print_expression_list COMMA print_expression
+			{
+				$$ = node($1, $3, END_NODE);
+			}
+
+print_expression
+		: expression
+			{
+				$$ = node($1, cs("ds.n"), END_NODE);
+			}
+		| STRING
+			{
+				char *p = escape($1);
+				$$ = node(cs("["), as(p), cs("]n"), END_NODE);
+				free(p);
+			}
+%%
+
+
+static void
+grow(void)
+{
+	struct tree	*p;
+	size_t		newsize;
+
+	if (current == instr_sz) {
+		newsize = instr_sz * 2 + 1;
+		p = realloc(instructions, newsize * sizeof(*p));
+		if (p == NULL) {
+			free(instructions);
+			err(1, NULL);
+		}
+		instructions = p;
+		instr_sz = newsize;
+	}
+}
+
+static ssize_t
+cs(const char *str)
+{
+	grow();
+	instructions[current].index = CONST_STRING;
+	instructions[current].u.cstr = str;
+	return current++;
+}
+
+static ssize_t
+as(const char *str)
+{
+	grow();
+	instructions[current].index = ALLOC_STRING;
+	instructions[current].u.astr = strdup(str);
+	if (instructions[current].u.astr == NULL)
+		err(1, NULL);
+	return current++;
+}
+
+static ssize_t
+node(ssize_t arg, ...)
+{
+	va_list		ap;
+	ssize_t		ret;
+
+	va_start(ap, arg);
+
+	ret = current;
+	grow();
+	instructions[current++].index = arg;
+
+	do {
+		arg = va_arg(ap, ssize_t);
+		grow();
+		instructions[current++].index = arg;
+	} while (arg != END_NODE);
+
+	va_end(ap);
+	return ret;
+}
+
+static void
+emit(ssize_t i)
+{
+	if (instructions[i].index >= 0)
+		while (instructions[i].index != END_NODE)
+			emit(instructions[i++].index);
+	else
+		fputs(instructions[i].u.cstr, stdout);
+}
+
+static void
+emit_macro(int node, ssize_t code)
+{
+	putchar('[');
+	emit(code);
+	printf("]s%s\n", instructions[node].u.cstr);
+	nesting--;
+}
+
+static void
+free_tree(void)
+{
+	ssize_t i;
+
+	for (i = 0; i < current; i++)
+		if (instructions[i].index == ALLOC_STRING)
+			free(instructions[i].u.astr);
+	current = 0;
+}
+
+static ssize_t
+numnode(int num)
+{
+	const char *p;
+
+	if (num < 10)
+		p = str_table['0' + num];
+	else if (num < 16)
+		p = str_table['A' - 10 + num];
+	else
+		errx(1, "internal error: break num > 15");
+	return node(cs(" "), cs(p), END_NODE);
+}
+
+
+static ssize_t
+lookup(char * str, size_t len, char type)
+{
+	ENTRY	entry, *found;
+	u_short	num;
+	u_char	*p;
+
+	/* The scanner allocated an extra byte already */
+	if (str[len-1] != type) {
+		str[len] = type;
+		str[len+1] = '\0';
+	}
+	entry.key = str;
+	found = hsearch(entry, FIND);
+	if (found == NULL) {
+		if (var_count == MAX_VARIABLES)
+			errx(1, "too many variables");
+		p = malloc(4);
+		if (p == NULL)
+			err(1, NULL);
+		num = var_count++;
+		p[0] = 255;
+		p[1] = ENCODE(num / VAR_BASE + 1);
+		p[2] = ENCODE(num % VAR_BASE + 1);
+		p[3] = '\0';
+
+		entry.data = (char *)p;
+		entry.key = strdup(str);
+		if (entry.key == NULL)
+			err(1, NULL);
+		found = hsearch(entry, ENTER);
+		if (found == NULL)
+			err(1, NULL);
+	}
+	return cs(found->data);
+}
+
+static ssize_t
+letter_node(char *str)
+{
+	size_t len;
+
+	len = strlen(str);
+	if (len == 1 && str[0] != '_')
+		return cs(str_table[(int)str[0]]);
+	else
+		return lookup(str, len, 'L');
+}
+
+static ssize_t
+array_node(char *str)
+{
+	size_t len;
+
+	len = strlen(str);
+	if (len == 1 && str[0] != '_')
+		return cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR]);
+	else
+		return lookup(str, len, 'A');
+}
+
+static ssize_t
+function_node(char *str)
+{
+	size_t len;
+
+	len = strlen(str);
+	if (len == 1 && str[0] != '_')
+		return cs(str_table[(int)str[0] - 'a' + FUNC_CHAR]);
+	else
+		return lookup(str, len, 'F');
+}
+
+static void
+add_par(ssize_t n)
+{
+	prologue = node(cs("S"), n, prologue, END_NODE);
+	epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
+}
+
+static void
+add_local(ssize_t n)
+{
+	prologue = node(cs("0S"), n, prologue, END_NODE);
+	epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
+}
+
+void
+yyerror(char *s)
+{
+	char	*str, *p;
+	int	n;
+
+	if (yyin != NULL && feof(yyin))
+		n = asprintf(&str, "%s: %s:%d: %s: unexpected EOF",
+		    __progname, filename, lineno, s);
+	else if (isspace(yytext[0]) || !isprint(yytext[0]))
+		n = asprintf(&str,
+		    "%s: %s:%d: %s: ascii char 0x%02x unexpected",
+		    __progname, filename, lineno, s, yytext[0]);
+	else
+		n = asprintf(&str, "%s: %s:%d: %s: %s unexpected",
+		    __progname, filename, lineno, s, yytext);
+	if (n == -1)
+		err(1, NULL);
+
+	fputs("c[", stdout);
+	for (p = str; *p != '\0'; p++) {
+		if (*p == '[' || *p == ']' || *p =='\\')
+			putchar('\\');
+		putchar(*p);
+	}
+	fputs("]pc\n", stdout);
+	free(str);
+}
+
+void
+fatal(const char *s)
+{
+	errx(1, "%s:%d: %s", filename, lineno, s);
+}
+
+static void
+warning(const char *s)
+{
+	warnx("%s:%d: %s", filename, lineno, s);
+}
+
+static void
+init(void)
+{
+	int i;
+
+	for (i = 0; i < UCHAR_MAX; i++) {
+		str_table[i][0] = i;
+		str_table[i][1] = '\0';
+	}
+	if (hcreate(1 << 16) == 0)
+		err(1, NULL);
+}
+
+
+static __dead2 void
+usage(void)
+{
+	fprintf(stderr, "usage: %s [-cl] [-e expression] [file ...]\n",
+	    __progname);
+	exit(1);
+}
+
+static char *
+escape(const char *str)
+{
+	char *ret, *p;
+
+	ret = malloc(strlen(str) + 1);
+	if (ret == NULL)
+		err(1, NULL);
+
+	p = ret;
+	while (*str != '\0') {
+		/*
+		 * We get _escaped_ strings here. Single backslashes are
+		 * already converted to double backslashes
+		 */
+		if (*str == '\\') {
+			if (*++str == '\\') {
+				switch (*++str) {
+				case 'a':
+					*p++ = '\a';
+					break;
+				case 'b':
+					*p++ = '\b';
+					break;
+				case 'f':
+					*p++ = '\f';
+					break;
+				case 'n':
+					*p++ = '\n';
+					break;
+				case 'q':
+					*p++ = '"';
+					break;
+				case 'r':
+					*p++ = '\r';
+					break;
+				case 't':
+					*p++ = '\t';
+					break;
+				case '\\':
+					*p++ = '\\';
+					break;
+				}
+				str++;
+			} else {
+				*p++ = '\\';
+				*p++ = *str++;
+			}
+		} else
+			*p++ = *str++;
+	}
+	*p = '\0';
+	return ret;
+}
+
+/* ARGSUSED */
+void
+sigchld(int signo)
+{
+	pid_t pid;
+	int status;
+
+	for (;;) {
+		pid = waitpid(dc, &status, WCONTINUED);
+		if (pid == -1) {
+			if (errno == EINTR)
+				continue;
+			_exit(0);
+		}
+		if (WIFEXITED(status) || WIFSIGNALED(status))
+			_exit(0);
+		else
+			break;
+	}
+}
+
+int
+main(int argc, char *argv[])
+{
+	int	i, ch;
+	int	p[2];
+	char	*q;
+
+	init();
+	setlinebuf(stdout);
+
+	sargv = malloc(argc * sizeof(char *));
+	if (sargv == NULL)
+		err(1, NULL);
+
+	if ((cmdexpr = strdup("")) == NULL)
+		err(1, NULL);
+	/* The d debug option is 4.4 BSD bc(1) compatible */
+	while ((ch = getopt(argc, argv, "cde:l")) != -1) {
+		switch (ch) {
+		case 'c':
+		case 'd':
+			do_fork = false;
+			break;
+		case 'e':
+			q = cmdexpr;
+			if (asprintf(&cmdexpr, "%s%s\n", cmdexpr, optarg) == -1)
+				err(1, NULL);
+			free(q);
+			break;
+		case 'l':
+			sargv[sargc++] = _PATH_LIBB;
+			break;
+		default:
+			usage();
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	interactive = isatty(STDIN_FILENO);
+	for (i = 0; i < argc; i++)
+		sargv[sargc++] = argv[i];
+
+	if (do_fork) {
+		if (pipe(p) == -1)
+			err(1, "cannot create pipe");
+		dc = fork();
+		if (dc == -1)
+			err(1, "cannot fork");
+		else if (dc != 0) {
+			signal(SIGCHLD, sigchld);
+			close(STDOUT_FILENO);
+			dup(p[1]);
+			close(p[0]);
+			close(p[1]);
+		} else {
+			close(STDIN_FILENO);
+			dup(p[0]);
+			close(p[0]);
+			close(p[1]);
+			execl(_PATH_DC, "dc", "-x", (char *)NULL);
+			err(1, "cannot find dc");
+		}
+	}
+	yywrap();
+	return yyparse();
+}
--- /dev/null
+++ usr.bin/bc/bc.library
@@ -0,0 +1,263 @@
+/*      $OpenBSD: bc.library,v 1.3 2007/02/03 21:15:06 otto Exp $	*/
+/*	$MidnightBSD: src/usr.bin/bc/bc.library,v 1.1 2007/08/25 18:43:20 archite Exp $ */
+
+/*
+ * Copyright (C) Caldera International Inc.  2001-2002.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code and documentation must retain the above
+ *    copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed or owned by Caldera
+ *      International, Inc.
+ * 4. Neither the name of Caldera International, Inc. nor the names of other
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
+ * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ *	@(#)bc.library	5.1 (Berkeley) 4/17/91
+ */
+
+scale = 20
+define e(x) {
+	auto a, b, c, d, e, g, t, w, y, r
+
+	r = ibase
+	ibase = A
+	t = scale
+	scale = t + .434*x + 1
+
+	w = 0
+	if (x < 0) {
+		x = -x
+		w = 1
+	}
+	y = 0
+	while (x > 2) {
+		x = x/2
+		y = y + 1
+	}
+
+	a = 1
+	b = 1
+	c = b
+	d = 1
+	e = 1
+	for (a = 1; 1 == 1; a++) {
+		b = b*x
+		c = c*a + b
+		d = d*a
+		g = c/d
+		if (g == e) {
+			g = g/1
+			while (y--) {
+				g = g*g
+			}
+			scale = t
+			ibase = r
+			if (w == 1) return (1/g)
+			return (g/1)
+		}
+		e = g
+	}
+}
+
+define l(x) {
+	auto a, b, c, d, e, f, g, u, s, t, r
+	r = ibase
+	ibase = A
+	if (x <= 0) {
+		a = (1 - 10^scale)
+		ibase = r
+		return (a)
+	}
+	t = scale
+
+	f = 1
+	scale = scale + scale(x) - length(x) + 1
+	s = scale
+	while (x > 2) {
+		s = s + (length(x) - scale(x))/2 + 1
+		if (s > 0) scale = s
+		x = sqrt(x)
+		f = f*2
+	}
+	while (x < .5) {
+		s = s + (length(x) - scale(x))/2 + 1
+		if (s > 0) scale = s
+		x = sqrt(x)
+		f = f*2
+	}
+
+	scale = t + length(f) - scale(f) + 1
+	u = (x - 1)/(x + 1)
+
+	scale = scale + 1.1*length(t) - 1.1*scale(t)
+	s = u*u
+	b = 2*f
+	c = b
+	d = 1
+	e = 1
+	for (a = 3; 1 == 1 ; a = a + 2) {
+		b = b*s
+		c = c*a + d*b
+		d = d*a
+		g = c/d
+		if (g == e) {
+			scale = t
+			ibase = r
+			return (u*c/d)
+		}
+		e = g
+	}
+}
+
+define s(x) {
+	auto a, b, c, s, t, y, p, n, i, r
+	r = ibase
+	ibase = A
+	t = scale
+	y = x/.7853
+	s = t + length(y) - scale(y)
+	if (s < t) s = t
+	scale = s
+	p = a(1)
+
+	scale = 0
+	if (x >= 0) n = (x/(2*p) + 1)/2
+	if (x < 0) n = (x/(2*p) - 1)/2
+	x = x - 4*n*p
+	if (n % 2 != 0) x = -x
+
+	scale = t + length(1.2*t) - scale(1.2*t)
+	y = -x*x
+	a = x
+	b = 1
+	s = x
+	for (i =3 ; 1 == 1; i = i + 2) {
+		a = a*y
+		b = b*i*(i - 1)
+		c = a/b
+		if (c == 0) {
+			scale = t
+			ibase = r
+			return (s/1)
+		}
+		s = s + c
+	}
+}
+
+define c(x) {
+	auto t, r
+	r = ibase
+	ibase = A
+	t = scale
+	scale = scale + 1
+	x = s(x + 2*a(1))
+	scale = t
+	ibase = r
+	return (x/1)
+}
+
+define a(x) {
+	auto a, b, c, d, e, f, g, s, t, r
+	if (x == 0) return(0)
+
+	r = ibase
+	ibase = A
+	if (x == 1) {
+		if (scale < 52) {
+			 a = .7853981633974483096156608458198757210492923498437764/1
+			 ibase = r
+			 return (a)
+		}
+	}
+	t = scale
+	f = 1
+	while (x > .5) {
+		scale = scale + 1
+		x = -(1 - sqrt(1. + x*x))/x
+		f = f*2
+	}
+	while (x < -.5) {
+		scale = scale + 1
+		x = -(1 - sqrt(1. + x*x))/x
+		f = f*2
+	}
+	s = -x*x
+	b = f
+	c = f
+	d = 1
+	e = 1
+	for (a = 3; 1 == 1; a = a + 2) {
+		b = b*s
+		c = c*a + d*b
+		d = d*a
+		g = c/d
+		if (g == e) {
+			ibase = r
+			scale = t
+			return (x*c/d)
+		}
+		e = g
+	}
+}
+
+define j(n,x) {
+	auto a, b, c, d, e, g, i, s, k, t, r
+
+	r = ibase
+	ibase = A
+	t = scale
+	k = 1.36*x + 1.16*t - n
+	k = length(k) - scale(k)
+	if (k > 0) scale = scale + k
+
+	s = -x*x/4
+	if (n < 0) {
+		n = -n
+		x = -x
+	}
+	a = 1
+	c = 1
+	for (i = 1; i <= n; i++) {
+		a = a*x
+		c = c*2*i
+	}
+	b = a
+	d = 1
+	e = 1
+	for (i = 1; 1; i++) {
+		a = a*s
+		b = b*i*(n + i) + a
+		c = c*i*(n + i)
+		g = b/c
+		if (g == e) {
+			ibase = r
+			scale = t
+			return (g/1)
+		}
+		e = g
+	}
+}
--- /dev/null
+++ usr.bin/bc/bc.1
@@ -0,0 +1,389 @@
+.\"	$OpenBSD: bc.1,v 1.22 2007/05/31 19:20:07 jmc Exp $
+.\"	$MidnightBSD: src/usr.bin/bc/bc.1,v 1.1 2007/08/25 18:43:20 archite Exp $
+.\"
+.\" Copyright (C) Caldera International Inc.  2001-2002.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code and documentation must retain the above
+.\"    copyright notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed or owned by Caldera
+.\"	International, Inc.
+.\" 4. Neither the name of Caldera International, Inc. nor the names of other
+.\"    contributors may be used to endorse or promote products derived from
+.\"    this software without specific prior written permission.
+.\"
+.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"	@(#)bc.1	6.8 (Berkeley) 8/8/91
+.\"
+.Dd $Mdocdate: May 31 2007 $
+.Dt BC 1
+.Sh NAME
+.Nm bc
+.Nd arbitrary-precision arithmetic language and calculator
+.Sh SYNOPSIS
+.Nm bc
+.Op Fl cl
+.Op Fl e Ar expression
+.Op Ar file ...
+.Sh DESCRIPTION
+.Nm
+is an interactive processor for a language which resembles
+C but provides unlimited precision arithmetic.
+It takes input from any expressions on the command line and
+any files given, then reads the standard input.
+.Pp
+Options available:
+.Bl -tag -width Ds
+.It Fl c
+.Nm
+is actually a preprocessor for
+.Xr dc 1 ,
+which it invokes automatically, unless the
+.Fl c
+.Pq compile only
+option is present.
+In this case the generated
+.Xr dc 1
+instructions are sent to the standard output,
+instead of being interpreted by a running
+.Xr dc 1
+process.
+.It Fl e Ar expression
+Evaluate
+.Ar expression .
+If multiple
+.Fl e
+options are specified, they are processed in the order given,
+separated by newlines.
+.It Fl l
+Allow specification of an arbitrary precision math library.
+The definitions in the library are available to command line
+expressions.
+.El
+.Pp
+The syntax for
+.Nm
+programs is as follows:
+.Sq L
+means letter a-z;
+.Sq E
+means expression;
+.Sq S
+means statement.
+As a non-portable extension, it is possible to use long names
+in addition to single letter names.
+A long name is a sequence starting with a lowercase letter
+followed by any number of lowercase letters and digits.
+The underscore character
+.Pq Sq _
+counts as a letter.
+.Pp
+Comments
+.Bd -unfilled -offset indent -compact
+are enclosed in /* and */
+are enclosed in # and the next newline
+.Ed
+.Pp
+The newline is not part of the line comment,
+which in itself is a non-portable extension.
+.Pp
+Names
+.Bd -unfilled -offset indent -compact
+simple variables: L
+array elements: L [ E ]
+The words `ibase', `obase', and `scale'
+The word `last' or a single dot
+.Ed
+.Pp
+Other operands
+.Bd -unfilled -offset indent -compact
+arbitrarily long numbers with optional sign and decimal point
+( E )
+sqrt ( E )
+length ( E )	number of significant decimal digits
+scale ( E )	number of digits right of decimal point
+L ( E , ... , E )
+.Ed
+.Pp
+The sequence
+.Sq \e<newline><whitespace>
+is ignored within numbers.
+.Pp
+Operators
+.Pp
+The following arithmetic and logical operators can be used.
+The semantics of the operators is the same as in the C language.
+They are listed in order of decreasing precedence.
+Operators in the same group have the same precedence.
+.Bl -column -offset indent "= += \-= *= /= %= ^=" "Associativity" \
+"multiply, divide, modulus"
+.It Sy "Operator" Ta Sy "Associativity" Ta Sy "Description"
+.It "++ \-\-" Ta "none" Ta "increment, decrement"
+.It "\-" Ta "none" Ta "unary minus"
+.It "^" Ta "right" Ta "power"
+.It "* / %" Ta "left" Ta "multiply, divide, modulus"
+.It "+ \-" Ta "left" Ta "plus, minus"
+.It "= += -= *= /= %= ^=" Ta "right" Ta "assignment"
+.It "== <= >= != < >" Ta "none" Ta "relational"
+.It "!" Ta "none" Ta "boolean not"
+.It "&&" Ta "left" Ta "boolean and"
+.It "||" Ta "left" Ta "boolean or"
+.El
+.Pp
+Note the following:
+.Bl -bullet -offset indent
+.It
+The relational operators may appear in any expression.
+The
+.St -p1003.2
+standard only allows them in the conditional expression of an
+.Sq if ,
+.Sq while
+or
+.Sq for
+statement.
+.It
+The relational operators have a lower precedence than the assignment
+operators.
+This has the consequence that the expression
+.Sy a = b < c
+is interpreted as
+.Sy (a = b) < c ,
+which is probably not what the programmer intended.
+.It
+In contrast with the C language, the relational operators all have
+the same precedence, and are non-associative.
+The expression
+.Sy a < b < c
+will produce a syntax error.
+.It
+The boolean operators (!, && and ||) are non-portable extensions.
+.It
+The boolean not
+(!) operator has much lower precedence than the same operator in the
+C language.
+This has the consequence that the expression
+.Sy !a < b
+is interpreted as
+.Sy !(a < b) .
+Prudent programmers use parentheses when writing expressions involving
+boolean operators.
+.El
+.Pp
+Statements
+.Bd -unfilled -offset indent -compact
+E
+{ S ; ... ; S }
+if ( E ) S
+if ( E ) S else S
+while ( E ) S
+for ( E ; E ; E ) S
+null statement
+break
+continue
+quit
+a string of characters, enclosed in double quotes
+print E ,..., E
+.Ed
+.Pp
+A string may contain any character, except double quote.
+The if statement with an else branch is a non-portable extension.
+All three E's in a for statement may be empty.
+This is a non-portable extension.
+The continue and print statements are also non-portable extensions.
+.Pp
+The print statement takes a list of comma-separated expressions.
+Each expression in the list is evaluated and the computed
+value is printed and assigned to the variable `last'.
+No trailing newline is printed.
+The expression may also be a string enclosed in double quotes.
+Within these strings the following escape sequences may be used:
+.Sq \ea
+for bell (alert),
+.Sq \eb
+for backspace,
+.Sq \ef
+for formfeed,
+.Sq \en
+for newline,
+.Sq \er
+for carriage return,
+.Sq \et
+for tab,
+.Sq \eq
+for double quote and
+.Sq \e\e
+for backslash.
+Any other character following a backslash will be ignored.
+Strings will not be assigned to `last'.
+.Pp
+Function definitions
+.Bd -unfilled -offset indent
+define L ( L ,..., L ) {
+	auto L, ... , L
+	S; ... S
+	return ( E )
+}
+.Ed
+.Pp
+As a non-portable extension, the opening brace of the define statement
+may appear on the next line.
+The return statement may also appear in the following forms:
+.Bd -unfilled -offset indent
+return
+return ()
+return E
+.Ed
+.Pp
+The first two are equivalent to the statement
+.Dq return 0 .
+The last form is a non-portable extension.
+Not specifying a return statement is equivalent to writing
+.Dq return (0) .
+.Pp
+Functions available in the math library, which is loaded by specifying the
+.Fl l
+flag on the command line
+.Pp
+.Bl -tag -width j(n,x) -offset indent -compact
+.It s(x)
+sine
+.It c(x)
+cosine
+.It e(x)
+exponential
+.It l(x)
+log
+.It a(x)
+arctangent
+.It j(n,x)
+Bessel function
+.El
+.Pp
+All function arguments are passed by value.
+.Pp
+The value of a statement that is an expression is printed
+unless the main operator is an assignment.
+The value printed is assigned to the special variable `last'.
+This is a non-portable extension.
+A single dot may be used as a synonym for `last'.
+Either semicolons or newlines may separate statements.
+Assignment to
+.Ar scale
+influences the number of digits to be retained on arithmetic
+operations in the manner of
+.Xr dc 1 .
+Assignments to
+.Ar ibase
+or
+.Ar obase
+set the input and output number radix respectively.
+.Pp
+The same letter may be used as an array, a function,
+and a simple variable simultaneously.
+All variables are global to the program.
+`Auto' variables are pushed down during function calls.
+When using arrays as function arguments
+or defining them as automatic variables,
+empty square brackets must follow the array name.
+.Pp
+For example
+.Bd -literal -offset indent
+scale = 20
+define e(x){
+	auto a, b, c, i, s
+	a = 1
+	b = 1
+	s = 1
+	for(i=1; 1==1; i++){
+		a = a*x
+		b = b*i
+		c = a/b
+		if(c == 0) return(s)
+		s = s+c
+	}
+}
+.Ed
+.Pp
+defines a function to compute an approximate value of
+the exponential function and
+.Pp
+.Dl for(i=1; i<=10; i++) e(i)
+.Pp
+prints approximate values of the exponential function of
+the first ten integers.
+.Bd -literal -offset indent
+$ bc -l -e 'scale = 500; 2 * a(2^10000)' -e quit
+.Ed
+.Pp
+prints an approximation of pi.
+.Sh FILES
+.Bl -tag -width /usr/share/misc/bc.library -compact
+.It Pa /usr/share/misc/bc.library
+math library, read when the
+.Fl l
+option is specified on the command line.
+.El
+.Sh SEE ALSO
+.Xr dc 1
+.Pp
+"BC \- An Arbitrary Precision Desk-Calculator Language",
+.Pa /usr/share/doc/usd/06.bc/ .
+.Sh STANDARDS
+The
+.Nm
+utility is compliant with the
+.St -p1003.1-2004
+specification.
+.Pp
+The flags
+.Op Fl ce
+are extensions to that specification.
+.Sh HISTORY
+The
+.Nm
+first command appeared in
+.At v6 .
+A complete rewrite of the
+.Nm
+command first appeared in
+.Ox 3.5 .
+.Sh AUTHORS
+.An -nosplit
+The original version of the
+.Nm
+command was written by
+.An Robert Morris
+and
+.An Lorinda Cherry .
+The current version of the
+.Nm
+utility was written by
+.An Otto Moerbeek .
+.Sh BUGS
+.Ql Quit
+is interpreted when read, not when executed.
+.Pp
+Some non-portable extensions, as found in the GNU version of the
+.Nm
+utility are not implemented (yet).
--- /dev/null
+++ usr.bin/bc/Makefile
@@ -0,0 +1,15 @@
+#	$OpenBSD: Makefile,v 1.4 2006/06/30 19:02:28 otto Exp $
+#	$MidnightBSD: src/usr.bin/bc/Makefile,v 1.1 2007/08/25 18:43:20 archite Exp $
+
+PROG=		bc
+SRCS=		bc.y scan.l
+CFLAGS+=	-I. -I${.CURDIR} -Wall -Wno-unused
+YFLAGS+=
+
+beforeinstall:
+	install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/bc.library \
+	    ${DESTDIR}/usr/share/misc
+
+SUBDIR+= USD.doc
+
+.include <bsd.prog.mk>
--- /dev/null
+++ usr.bin/bc/pathnames.h
@@ -0,0 +1,21 @@
+/*      $OpenBSD: pathnames.h,v 1.1 2003/09/25 19:32:44 otto Exp $	*/
+/*	$MidnightBSD: src/usr.bin/bc/pathnames.h,v 1.1 2007/08/25 18:43:20 archite Exp $ */
+
+/*
+ * Copyright (c) 2003, Otto Moerbeek <otto at drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define	_PATH_LIBB	"/usr/share/misc/bc.library"
+#define	_PATH_DC	"/usr/bin/dc"
Index: Makefile
===================================================================
RCS file: /home/cvs/src/usr.bin/Makefile,v
retrieving revision 1.10
retrieving revision 1.11
diff -Lusr.bin/Makefile -Lusr.bin/Makefile -u -r1.10 -r1.11
--- usr.bin/Makefile
+++ usr.bin/Makefile
@@ -16,6 +16,7 @@
 	awk \
 	banner \
 	basename \
+	bc \
 	biff \
 	${_bluetooth} \
 	brandelf \
@@ -45,6 +46,7 @@
 	${_csup} \
 	ctags \
 	cut \
+	dc \
 	deroff \
 	${_dig} \
 	dirname \
--- /dev/null
+++ usr.bin/dc/extern.h
@@ -0,0 +1,63 @@
+/*	$OpenBSD: extern.h,v 1.3 2006/01/16 08:09:25 otto Exp $	*/
+/*	$MidnightBSD: src/usr.bin/dc/extern.h,v 1.1 2007/08/25 18:43:21 archite Exp $ */
+
+/*
+ * Copyright (c) 2003, Otto Moerbeek <otto at drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include "bcode.h"
+
+
+/* inout.c */
+void		src_setstream(struct source *, FILE *);
+void		src_setstring(struct source *, char *);
+struct number	*readnumber(struct source *, u_int);
+void		printnumber(FILE *, const struct number *, u_int);
+char		*read_string(struct source *);
+void		print_value(FILE *, const struct value *, const char *, u_int);
+void		print_ascii(FILE *, const struct number *);
+
+/* mem.c */
+struct number	*new_number(void);
+void		free_number(struct number *);
+struct number	*dup_number(const struct number *);
+void		*bmalloc(size_t);
+void		*brealloc(void *, size_t);
+char		*bstrdup(const char *p);
+void		bn_check(int);
+void		bn_checkp(const void *);
+
+/* stack.c */
+void		stack_init(struct stack *);
+void		stack_free_value(struct value *);
+struct value	*stack_dup_value(const struct value *, struct value *);
+void		stack_swap(struct stack *);
+size_t		stack_size(const struct stack *);
+void		stack_dup(struct stack *);
+void		stack_pushnumber(struct stack *, struct number *);
+void		stack_pushstring(struct stack *stack, char *);
+void		stack_push(struct stack *, struct value *);
+void		stack_set_tos(struct stack *, struct value *);
+struct value	*stack_tos(const struct stack *);
+struct value	*stack_pop(struct stack *);
+struct number	*stack_popnumber(struct stack *);
+char *		stack_popstring(struct stack *);
+void		stack_clear(struct stack *);
+void		stack_print(FILE *, const struct stack *, const char *,
+		    u_int base);
+void		frame_assign(struct stack *, size_t, const struct value *);
+struct value *	frame_retrieve(const struct stack *, size_t);
+/* void		frame_free(struct stack *); */
--- /dev/null
+++ usr.bin/dc/mem.c
@@ -0,0 +1,109 @@
+/*	$OpenBSD: mem.c,v 1.4 2004/07/11 06:41:48 otto Exp $	*/
+/*	$MidnightBSD: src/usr.bin/dc/mem.c,v 1.1 2007/08/25 18:43:21 archite Exp $ */
+
+/*
+ * Copyright (c) 2003, Otto Moerbeek <otto at drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$MidnightBSD: src/usr.bin/dc/mem.c,v 1.1 2007/08/25 18:43:21 archite Exp $";
+#endif /* not lint */
+
+#include <openssl/err.h>
+
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "extern.h"
+
+struct number *
+new_number(void)
+{
+	struct number *n;
+
+	n = bmalloc(sizeof(*n));
+	n->scale = 0;
+	n->number = BN_new();
+	if (n->number == NULL)
+		err(1, NULL);
+	return n;
+}
+
+void
+free_number(struct number *n)
+{
+	BN_free(n->number);
+	free(n);
+}
+
+struct number *
+dup_number(const struct number *a)
+{
+	struct number *n;
+
+	n = bmalloc(sizeof(*n));
+	n->scale = a->scale;
+	n->number = BN_dup(a->number);
+	bn_checkp(n->number);
+	return n;
+}
+
+void *
+bmalloc(size_t sz)
+{
+	void *p;
+
+	p = malloc(sz);
+	if (p == NULL)
+		err(1, NULL);
+	return p;
+}
+
+void *
+brealloc(void *p, size_t sz)
+{
+	void *q;
+
+	q = realloc(p, sz);
+	if (q == NULL)
+		err(1, NULL);
+	return q;
+}
+
+char *
+bstrdup(const char *p)
+{
+	char *q;
+
+	q = strdup(p);
+	if (q == NULL)
+		err(1, NULL);
+	return q;
+}
+
+void
+bn_check(int x)						\
+{
+	if (x == 0)
+		err(1, "big number failure %lx", ERR_get_error());
+}
+
+void
+bn_checkp(const void *p)						\
+{
+	if (p == NULL)
+		err(1, "allocation failure %lx", ERR_get_error());
+}
--- /dev/null
+++ usr.bin/dc/inout.c
@@ -0,0 +1,416 @@
+/*	$OpenBSD: inout.c,v 1.14 2006/01/15 19:11:59 otto Exp $	*/
+/*	$MidnightBSD: src/usr.bin/dc/inout.c,v 1.1 2007/08/25 18:43:21 archite Exp $ */
+
+/*
+ * Copyright (c) 2003, Otto Moerbeek <otto at drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$MidnightBSD: src/usr.bin/dc/inout.c,v 1.1 2007/08/25 18:43:21 archite Exp $";
+#endif /* not lint */
+
+#include <openssl/ssl.h>
+#include <ctype.h>
+#include <err.h>
+#include <string.h>
+
+#include "extern.h"
+
+#define MAX_CHARS_PER_LINE 68
+
+static int	lastchar;
+static int	charcount;
+
+static int	src_getcharstream(struct source *);
+static void	src_ungetcharstream(struct source *);
+static char	*src_getlinestream(struct source *);
+static void	src_freestream(struct source *);
+static int	src_getcharstring(struct source *);
+static void	src_ungetcharstring(struct source *);
+static char	*src_getlinestring(struct source *);
+static void	src_freestring(struct source *);
+static void	flushwrap(FILE *);
+static void	putcharwrap(FILE *, int);
+static void	printwrap(FILE *, const char *);
+static char	*get_digit(u_long, int, u_int);
+
+static struct vtable stream_vtable = {
+	src_getcharstream,
+	src_ungetcharstream,
+	src_getlinestream,
+	src_freestream
+};
+
+static struct vtable string_vtable = {
+	src_getcharstring,
+	src_ungetcharstring,
+	src_getlinestring,
+	src_freestring
+};
+
+void
+src_setstream(struct source *src, FILE *stream)
+{
+	src->u.stream = stream;
+	src->vtable = &stream_vtable;
+}
+
+void
+src_setstring(struct source *src, char *p)
+{
+	src->u.string.buf = (u_char *)p;
+	src->u.string.pos = 0;
+	src->vtable = &string_vtable;
+}
+
+static int
+src_getcharstream(struct source *src)
+{
+	return src->lastchar = getc(src->u.stream);
+}
+
+static void
+src_ungetcharstream(struct source *src)
+{
+	(void)ungetc(src->lastchar, src->u.stream);
+}
+
+/* ARGSUSED */
+static void
+src_freestream(struct source *src)
+{
+}
+
+static char *
+src_getlinestream(struct source *src)
+{
+	char buf[BUFSIZ];
+
+	if (fgets(buf, BUFSIZ, src->u.stream) == NULL)
+		return bstrdup("");
+	return bstrdup(buf);
+}
+
+static int
+src_getcharstring(struct source *src)
+{
+	src->lastchar = src->u.string.buf[src->u.string.pos];
+	if (src->lastchar == '\0')
+		return EOF;
+	else {
+		src->u.string.pos++;
+		return src->lastchar;
+	}
+}
+
+static void
+src_ungetcharstring(struct source *src)
+{
+	if (src->u.string.pos > 0) {
+		if (src->lastchar != '\0')
+			--src->u.string.pos;
+	}
+}
+
+static char *
+src_getlinestring(struct source *src)
+{
+	char buf[BUFSIZ];
+	int ch, i;
+
+	i = 0;
+	while (i < BUFSIZ-1) {
+		ch = src_getcharstring(src);
+		if (ch == EOF)
+			break;
+		buf[i++] = ch;
+		if (ch == '\n')
+			break;
+	}
+	buf[i] = '\0';
+	return bstrdup(buf);
+}
+
+static void
+src_freestring(struct source *src)
+{
+	free(src->u.string.buf);
+}
+
+static void
+flushwrap(FILE *f)
+{
+	if (lastchar != -1)
+		(void)putc(lastchar, f);
+}
+
+static void
+putcharwrap(FILE *f, int ch)
+{
+	if (charcount >= MAX_CHARS_PER_LINE) {
+		charcount = 0;
+		(void)fputs("\\\n", f);
+	}
+	if (lastchar != -1) {
+		charcount++;
+		(void)putc(lastchar, f);
+	}
+	lastchar = ch;
+}
+
+static void
+printwrap(FILE *f, const char *p)
+{
+	char	buf[12];
+	char	*q = buf;
+
+	(void)strlcpy(buf, p, sizeof(buf));
+	while (*q)
+		putcharwrap(f, *q++);
+}
+
+struct number *
+readnumber(struct source *src, u_int base)
+{
+	struct number	*n;
+	int		ch;
+	bool		sign = false;
+	bool		dot = false;
+	BN_ULONG	v;
+	u_int		i;
+
+	n = new_number();
+	bn_check(BN_zero(n->number));
+
+	while ((ch = (*src->vtable->readchar)(src)) != EOF) {
+
+		if ('0' <= ch && ch <= '9')
+			v = ch - '0';
+		else if ('A' <= ch && ch <= 'F')
+			v = ch - 'A' + 10;
+		else if (ch == '_') {
+			sign = true;
+			continue;
+		} else if (ch == '.') {
+			if (dot)
+				break;
+			dot = true;
+			continue;
+		} else {
+			(*src->vtable->unreadchar)(src);
+			break;
+		}
+		if (dot)
+			n->scale++;
+
+		bn_check(BN_mul_word(n->number, base));
+
+#if 0
+		/* work around a bug in BN_add_word: 0 += 0 is buggy.... */
+		if (v > 0)
+#endif
+			bn_check(BN_add_word(n->number, v));
+	}
+	if (base != 10) {
+		scale_number(n->number, n->scale);
+		for (i = 0; i < n->scale; i++)
+			(void)BN_div_word(n->number, base);
+	}
+	if (sign)
+		negate(n);
+	return n;
+}
+
+char *
+read_string(struct source *src)
+{
+	int count, i, sz, new_sz, ch;
+	char *p;
+	bool escape;
+
+	escape = false;
+	count = 1;
+	i = 0;
+	sz = 15;
+	p = bmalloc(sz + 1);
+
+	while ((ch = (*src->vtable->readchar)(src)) != EOF) {
+		if (!escape) {
+			if (ch == '[')
+				count++;
+			else if (ch == ']')
+				count--;
+			if (count == 0)
+				break;
+		}
+		if (ch == '\\' && !escape)
+			escape = true;
+		else {
+			escape = false;
+			if (i == sz) {
+				new_sz = sz * 2;
+				p = brealloc(p, new_sz + 1);
+				sz = new_sz;
+			}
+			p[i++] = ch;
+		}
+	}
+	p[i] = '\0';
+	return p;
+}
+
+static char *
+get_digit(u_long num, int digits, u_int base)
+{
+	char *p;
+
+	if (base <= 16) {
+		p = bmalloc(2);
+		p[0] = num >= 10 ? num + 'A' - 10 : num + '0';
+		p[1] = '\0';
+	} else {
+		if (asprintf(&p, "%0*lu", digits, num) == -1)
+			err(1, NULL);
+	}
+	return p;
+}
+
+void
+printnumber(FILE *f, const struct number *b, u_int base)
+{
+	struct number	*int_part, *fract_part;
+	int		digits;
+	char		buf[11];
+	size_t		sz;
+	int		i;
+	struct stack	stack;
+	char		*p;
+
+	charcount = 0;
+	lastchar = -1;
+	if (BN_is_zero(b->number))
+		putcharwrap(f, '0');
+
+	int_part = new_number();
+	fract_part = new_number();
+	fract_part->scale = b->scale;
+
+	if (base <= 16)
+		digits = 1;
+	else {
+		digits = snprintf(buf, sizeof(buf), "%u", base-1);
+	}
+	split_number(b, int_part->number, fract_part->number);
+
+	i = 0;
+	stack_init(&stack);
+	while (!BN_is_zero(int_part->number)) {
+		BN_ULONG rem = BN_div_word(int_part->number, base);
+		stack_pushstring(&stack, get_digit(rem, digits, base));
+		i++;
+	}
+	sz = i;
+	if (BN_cmp(b->number, &zero) < 0)
+		putcharwrap(f, '-');
+	for (i = 0; i < sz; i++) {
+		p = stack_popstring(&stack);
+		if (base > 16)
+			putcharwrap(f, ' ');
+		printwrap(f, p);
+		free(p);
+	}
+	stack_clear(&stack);
+	if (b->scale > 0) {
+		struct number	*num_base;
+		BIGNUM		mult, stop;
+
+		putcharwrap(f, '.');
+		num_base = new_number();
+		bn_check(BN_set_word(num_base->number, base));
+		BN_init(&mult);
+		bn_check(BN_one(&mult));
+		BN_init(&stop);
+		bn_check(BN_one(&stop));
+		scale_number(&stop, b->scale);
+
+		i = 0;
+		while (BN_cmp(&mult, &stop) < 0) {
+			u_long	rem;
+
+			if (i && base > 16)
+				putcharwrap(f, ' ');
+			i = 1;
+
+			bmul_number(fract_part, fract_part, num_base);
+			split_number(fract_part, int_part->number, NULL);
+			rem = BN_get_word(int_part->number);
+			p = get_digit(rem, digits, base);
+			int_part->scale = 0;
+			normalize(int_part, fract_part->scale);
+			bn_check(BN_sub(fract_part->number, fract_part->number,
+			    int_part->number));
+			printwrap(f, p);
+			free(p);
+			bn_check(BN_mul_word(&mult, base));
+		}
+		free_number(num_base);
+		BN_free(&mult);
+		BN_free(&stop);
+	}
+	flushwrap(f);
+	free_number(int_part);
+	free_number(fract_part);
+}
+
+void
+print_value(FILE *f, const struct value *value, const char *prefix, u_int base)
+{
+	(void)fputs(prefix, f);
+	switch (value->type) {
+	case BCODE_NONE:
+		if (value->array != NULL)
+			(void)fputs("<array>", f);
+		break;
+	case BCODE_NUMBER:
+		printnumber(f, value->u.num, base);
+		break;
+	case BCODE_STRING:
+		(void)fputs(value->u.string, f);
+		break;
+	}
+}
+
+void
+print_ascii(FILE *f, const struct number *n)
+{
+	BIGNUM *v;
+	int numbits, i, ch;
+
+	v = BN_dup(n->number);
+	bn_checkp(v);
+
+	if (BN_cmp(v, &zero) < 0)
+		bn_check(BN_sub(v, &zero, v));
+
+	numbits = BN_num_bytes(v) * 8;
+	while (numbits > 0) {
+		ch = 0;
+		for (i = 0; i < 8; i++)
+			ch |= BN_is_bit_set(v, numbits-i-1) << (7 - i);
+		(void)putc(ch, f);
+		numbits -= 8;
+	}
+	BN_free(v);
+}
--- /dev/null
+++ usr.bin/dc/dc.c
@@ -0,0 +1,118 @@
+/*	$OpenBSD: dc.c,v 1.10 2007/07/29 17:12:18 sobrado Exp $	*/
+/*	$MidnightBSD: src/usr.bin/dc/dc.c,v 1.1 2007/08/25 18:43:21 archite Exp $
+
+/*
+ * Copyright (c) 2003, Otto Moerbeek <otto at drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$MidnightBSD: src/usr.bin/dc/dc.c,v 1.1 2007/08/25 18:43:21 archite Exp $";
+#endif /* not lint */
+
+#include <sys/stat.h>
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+static __dead2 void	usage(void);
+
+extern char		*__progname;
+
+static __dead2 void
+usage(void)
+{
+	(void)fprintf(stderr, "usage: %s [-x] [-e expression] [file]\n",
+	    __progname);
+	exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int		ch;
+	bool		extended_regs = false;
+	FILE		*file;
+	struct source	src;
+	char		*buf, *p;
+	struct stat	st;
+
+
+	if ((buf = strdup("")) == NULL)
+		err(1, NULL);
+	/* accept and ignore a single dash to be 4.4BSD dc(1) compatible */
+	while ((ch = getopt(argc, argv, "e:x-")) != -1) {
+		switch (ch) {
+		case 'e':
+			p = buf;
+			if (asprintf(&buf, "%s %s", buf, optarg) == -1)
+				err(1, NULL);
+			free(p);
+			break;
+		case 'x':
+			extended_regs = true;
+			break;
+		case '-':
+			break;
+		default:
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	init_bmachine(extended_regs);
+	(void)setlinebuf(stdout);
+	(void)setlinebuf(stderr);
+
+	if (argc > 1)
+		usage();
+	if (buf[0] != '\0') {
+		src_setstring(&src, buf);
+		reset_bmachine(&src);
+		eval();
+		free(buf);
+		if (argc == 0)
+			return (0);
+	}
+	if (argc == 1) {
+		file = fopen(argv[0], "r");
+		if (file == NULL)
+			err(1, "cannot open file %s", argv[0]);
+		if (fstat(fileno(file), &st) == -1)
+			err(1, "%s", argv[0]);
+		if (S_ISDIR(st.st_mode)) {
+			errno = EISDIR;
+			err(1, "%s", argv[0]);
+		}
+		src_setstream(&src, file);
+		reset_bmachine(&src);
+		eval();
+		(void)fclose(file);
+		/*
+		 * BSD and Solaris dc(1) continue with stdin after processing
+		 * the file given as the argument. We follow GNU dc(1).
+		 */
+		 return (0);
+	}
+	src_setstream(&src, stdin);
+	reset_bmachine(&src);
+	eval();
+
+	return (0);
+}
--- /dev/null
+++ usr.bin/dc/dc.1
@@ -0,0 +1,537 @@
+.\"	$OpenBSD: dc.1,v 1.23 2007/05/31 19:20:09 jmc Exp $
+.\"	$MidnightBSD: src/usr.bin/dc/dc.1,v 1.1 2007/08/25 18:43:21 archite Exp $
+.\"
+.\" Copyright (C) Caldera International Inc.  2001-2002.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code and documentation must retain the above
+.\"    copyright notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed or owned by Caldera
+.\"	International, Inc.
+.\" 4. Neither the name of Caldera International, Inc. nor the names of other
+.\"    contributors may be used to endorse or promote products derived from
+.\"    this software without specific prior written permission.
+.\"
+.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"	@(#)dc.1	8.1 (Berkeley) 6/6/93
+.\"
+.Dd $Mdocdate: May 31 2007 $
+.Dt DC 1
+.Sh NAME
+.Nm dc
+.Nd desk calculator
+.Sh SYNOPSIS
+.Nm
+.Op Fl x
+.Op Fl e Ar expression
+.Op Ar file
+.Sh DESCRIPTION
+.Nm
+is an arbitrary precision arithmetic package.
+The overall structure of
+.Nm
+is
+a stacking (reverse Polish) calculator i.e.\&
+numbers are stored on a stack.
+Adding a number pushes it onto the stack.
+Arithmetic operations pop arguments off the stack
+and push the results.
+See also the
+.Xr bc 1
+utility, which is a preprocessor for
+.Nm
+providing infix notation and a C-like syntax
+which implements functions and reasonable control
+structures for programs.
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl e Ar expression
+Evaluate
+.Ar expression .
+If multiple
+.Fl e
+options are specified, they will be processed in the order given.
+If no
+.Ar file
+argument is given, execution will stop after processing the expressions
+given on the command line,
+otherwise processing will continue with the contents of
+.Ar file .
+.It Fl x
+Enable extended register mode.
+This mode is used by
+.Xr bc 1
+to allow more than 256 registers.
+See
+.Sx Registers
+for a more detailed description.
+.El
+.Pp
+Ordinarily,
+.Nm
+operates on decimal integers,
+but one may specify an input base, output base,
+and a number of fractional digits (scale) to be maintained.
+If an argument is given,
+input is taken from that file until its end,
+then from the standard input.
+Whitespace is ignored, except where it signals the end of a number,
+end of a line or when a register name is expected.
+The following constructions are recognized:
+.Bl -tag -width "number"
+.It Va number
+The value of the number is pushed on the stack.
+A number is an unbroken string of the digits 0\-9 and letters A\-F.
+It may be preceded by an underscore
+.Pq Sq _
+to input a negative number.
+A number may contain a single decimal point.
+A number may also contain the characters A\-F, with the values 10\-15.
+.It Cm "+ - / * % ~ ^"
+The
+top two values on the stack are added
+(+),
+subtracted
+(\-),
+multiplied (*),
+divided (/),
+remaindered (%),
+divided and remaindered (~),
+or exponentiated (^).
+The two entries are popped off the stack;
+the result is pushed on the stack in their place.
+Any fractional part of an exponent is ignored.
+.Pp
+For addition and subtraction, the scale of the result is the maximum
+of scales of the operands.
+For division the scale of the result is defined
+by the scale set by the
+.Ic k
+operation.
+For multiplication, the scale is defined by the expression
+.Sy min(a+b,max(a,b,scale)) ,
+where
+.Sy a
+and
+.Sy b
+are the scales of the operands, and
+.Sy scale
+is the scale defined by the
+.Ic k
+operation.
+For exponentiation with a non-negative exponent, the scale of the result is
+.Sy min(a*b,max(scale,a)) ,
+where
+.Sy a
+is the scale of the base, and
+.Sy b
+is the
+.Em value
+of the exponent.
+If the exponent is negative, the scale of the result is the scale
+defined by the
+.Ic k
+operation.
+.Pp
+In the case of the division and modulus operator (~),
+the resultant quotient is pushed first followed by the remainder.
+This is a shorthand for the sequence:
+.Bd -literal -offset indent -compact
+x y / x y %
+.Ed
+The division and modulus operator is a non-portable extension.
+.It Ic a
+Pop the top value from the stack.
+If that value is a number, compute the integer part of the number modulo 256.
+If the result is zero, push an empty string.
+Otherwise push a one character string by interpreting the computed value
+as an
+.Tn ASCII
+character.
+.Pp
+If the top value is a string, push a string containing the first character
+of the original string.
+If the original string is empty, an empty string is pushed back.
+The
+.Ic a
+operator is a non-portable extension.
+.It Ic c
+All values on the stack are popped.
+.It Ic d
+The top value on the stack is duplicated.
+.It Ic f
+All values on the stack are printed, separated by newlines.
+.It Ic G
+The top two numbers are popped from the stack and compared.
+A one is pushed if the top of the stack is equal to the second number
+on the stack.
+A zero is pushed otherwise.
+This is a non-portable extension.
+.It Ic I
+Pushes the input base on the top of the stack.
+.It Ic i
+The top value on the stack is popped and used as the
+base for further input.
+The initial input base is 10.
+.It Ic J
+Pop the top value from the stack.
+The recursion level is popped by that value and, following that,
+the input is skipped until the first occurrence of the
+.Ic M
+operator.
+The
+.Ic J
+operator is a non-portable extension, used by the
+.Xr bc 1
+command.
+.It Ic K
+The current scale factor is pushed onto the stack.
+.It Ic k
+The top of the stack is popped, and that value is used as
+a non-negative scale factor:
+the appropriate number of places
+are printed on output,
+and maintained during multiplication, division, and exponentiation.
+The interaction of scale factor,
+input base, and output base will be reasonable if all are changed
+together.
+.It Ic L Ns Ar x
+Register
+.Ar x
+is treated as a stack and its top value is popped onto the main stack.
+.It Ic l Ns Ar x
+The
+value in register
+.Ar x
+is pushed on the stack.
+The register
+.Ar x
+is not altered.
+Initially, all registers contain the value zero.
+.It Ic M
+Mark used by the
+.Ic J
+operator.
+The
+.Ic M
+operator is a non-portable extensions, used by the
+.Xr bc 1
+command.
+.It Ic N
+The top of the stack is replaced by one if the top of the stack
+is equal to zero.
+If the top of the stack is unequal to zero, it is replaced by zero.
+This is a non-portable extension.
+.It Ic n
+The top value on the stack is popped and printed without a newline.
+This is a non-portable extension.
+.It Ic O
+Pushes the output base on the top of the stack.
+.It Ic o
+The top value on the stack is popped and used as the
+base for further output.
+The initial output base is 10.
+.It Ic P
+The top of the stack is popped.
+If the top of the stack is a string, it is printed without a trailing newline.
+If the top of the stack is a number, it is interpreted as a
+base 256 number, and each digit of this base 256 number is printed as
+an
+.Tn ASCII
+character, without a trailing newline.
+.It Ic p
+The top value on the stack is printed with a trailing newline.
+The top value remains unchanged.
+.It Ic Q
+The top value on the stack is popped and the string execution level is popped
+by that value.
+.It Ic q
+Exits the program.
+If executing a string, the recursion level is
+popped by two.
+.It Ic R
+The top of the stack is removed (popped).
+This is a non-portable extension.
+.It Ic r
+The top two values on the stack are reversed (swapped).
+This is a non-portable extension.
+.It Ic S Ns Ar x
+Register
+.Ar x
+is treated as a stack.
+The top value of the main stack is popped and pushed on it.
+.It Ic s Ns Ar x
+The
+top of the stack is popped and stored into
+a register named
+.Ar x .
+.It Ic v
+Replaces the top element on the stack by its square root.
+The scale of the result is the maximum of the scale of the argument
+and the current value of scale.
+.It Ic X
+Replaces the number on the top of the stack with its scale factor.
+If the top of the stack is a string, replace it with the integer 0.
+.It Ic x
+Treats the top element of the stack as a character string
+and executes it as a string of
+.Nm
+commands.
+.It Ic Z
+Replaces the number on the top of the stack with its length.
+The length of a string is its number of characters.
+The length of a number is its number of digits, not counting the minus sign
+and decimal point.
+.It Ic z
+The stack level is pushed onto the stack.
+.It Cm [ Ns ... Ns Cm ]
+Puts the bracketed
+.Tn ASCII
+string onto the top of the stack.
+If the string includes brackets, these must be properly balanced.
+The backslash character
+.Pq Sq \e
+may be used as an escape character, making it
+possible to include unbalanced brackets in strings.
+To include a backslash in a string, use a double backslash.
+.It Xo
+.Cm < Ns Va x
+.Cm > Ns Va x
+.Cm = Ns Va x
+.Cm !< Ns Va x
+.Cm !> Ns Va x
+.Cm != Ns Va x
+.Xc
+The top two elements of the stack are popped and compared.
+Register
+.Ar x
+is executed if they obey the stated
+relation.
+.It Xo
+.Cm < Ns Va x Ns e Ns Va y
+.Cm > Ns Va x Ns e Ns Va y
+.Cm = Ns Va x Ns e Ns Va y
+.Cm !< Ns Va x Ns e Ns Va y
+.Cm !> Ns Va x Ns e Ns Va y
+.Cm != Ns Va x Ns e Ns Va y
+.Xc
+These operations are variants of the comparison operations above.
+The first register name is followed by the letter
+.Sq e
+and another register name.
+Register
+.Ar x
+will be executed if the relation is true, and register
+.Ar y
+will be executed if the relation is false.
+This is a non-portable extension.
+.It Ic \&(
+The top two numbers are popped from the stack and compared.
+A one is pushed if the top of the stack is less than the second number
+on the stack.
+A zero is pushed otherwise.
+This is a non-portable extension.
+.It Ic {
+The top two numbers are popped from the stack and compared.
+A one is pushed if the top of stack is less than or equal to the
+second number on the stack.
+A zero is pushed otherwise.
+This is a non-portable extension.
+.It Ic \&!
+Interprets the rest of the line as a
+.Ux
+command.
+.It Ic \&?
+A line of input is taken from the input source (usually the terminal)
+and executed.
+.It Ic : Ns Ar r
+Pop two values from the stack.
+The second value on the stack is stored into the array
+.Ar r
+indexed by the top of stack.
+.It Ic ; Ns Ar r
+Pop a value from the stack.
+The value is used as an index into register
+.Ar r .
+The value in this register is pushed onto the stack.
+.Pp
+Array elements initially have the value zero.
+Each level of a stacked register has its own array associated with
+it.
+The command sequence
+.Bd -literal -offset indent
+[first] 0:a [dummy] Sa [second] 0:a 0;a p La 0;a p
+.Ed
+.Pp
+will print
+.Bd -literal -offset indent
+second
+first
+.Ed
+.Pp
+since the string
+.Ql second
+is written in an array that is later popped, to reveal the array that
+stored
+.Ql first .
+.It Ic #
+Skip the rest of the line.
+This is a non-portable extension.
+.El
+.Ss Registers
+Registers have a single character name
+.Ar x ,
+where
+.Ar x
+may be any character, including space, tab or any other special character.
+If extended register mode is enabled using the
+.Fl x
+option and the register identifier
+.Ar x
+has the value 255, the next two characters are interpreted as a
+two-byte register index.
+The set of standard single character registers and the set of extended
+registers do not overlap.
+Extended register mode is a non-portable extension.
+.Sh EXAMPLES
+An example which prints the first ten values of
+.Ic n! :
+.Bd -literal -offset indent
+[la1+dsa*pla10>y]sy
+0sa1
+lyx
+.Ed
+.Pp
+Independent of the current input base, the command
+.Bd -literal -offset indent
+Ai
+.Ed
+.Pp
+will reset the input base to decimal 10.
+.Sh DIAGNOSTICS
+.Bl -diag
+.It %c (0%o) is unimplemented
+an undefined operation was called.
+.It stack empty
+for not enough elements on the stack to do what was asked.
+.It stack register '%c' (0%o) is empty
+for an
+.Ar L
+operation from a stack register that is empty.
+.It Runtime warning: non-zero scale in exponent
+for a fractional part of an exponent that is being ignored.
+.It divide by zero
+for trying to divide by zero.
+.It remainder by zero
+for trying to take a remainder by zero.
+.It square root of negative number
+for trying to take the square root of a negative number.
+.It index too big
+for an array index that is larger than 2048.
+.It negative index
+for a negative array index.
+.It "input base must be a number between 2 and 16"
+for trying to set an illegal input base.
+.It output base must be a number greater than 1
+for trying to set an illegal output base.
+.It scale must be a nonnegative number
+for trying to set a negative or zero scale.
+.It scale too large
+for trying to set a scale that is too large.
+A scale must be representable as a 32-bit unsigned number.
+.It Q command argument exceeded string execution depth
+for trying to pop the recursion level more than the current
+recursion level.
+.It Q command requires a number >= 1
+for trying to pop an illegal number of recursion levels.
+.It recursion too deep
+for too many levels of nested execution.
+.Pp
+The recursion level is increased by one if the
+.Ar x
+or
+.Ar ?\&
+operation or one of the compare operations resulting in the execution
+of register is executed.
+As an exception, the recursion level is not increased if the operation
+is executed as the last command of a string.
+For example, the commands
+.Bd -literal -offset indent
+[lax]sa
+1 lax
+.Ed
+.Pp
+will execute an endless loop, while the commands
+.Bd -literal -offset indent
+[laxp]sa
+1 lax
+.Ed
+.Pp
+will terminate because of a too deep recursion level.
+.It J command argument exceeded string execution depth
+for trying to pop the recursion level more than the current
+recursion level.
+.It mark not found
+for a failed scan for an occurrence of the
+.Ic M
+operator.
+.El
+.Sh SEE ALSO
+.Xr bc 1
+.Rs
+.%B USD:05
+.%A L. L. Cherry
+.%A R. Morris
+.%T "DC \- An Interactive Desk Calculator"
+.Re
+.Sh STANDARDS
+The arithmetic operations of the
+.Nm
+utility are expected to conform to the definition listed in the
+.Xr bc 1
+section of the
+.St -p1003.2
+specification.
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.At v6 .
+A complete rewrite of the
+.Nm
+command using the
+.Xr bn 3
+big number routines first appeared in
+.Ox 3.5 .
+.Sh AUTHORS
+.An -nosplit
+The original version of the
+.Nm
+command was written by
+.An Robert Morris
+and
+.An Lorinda Cherry .
+The current version of the
+.Nm
+utility was written by
+.An Otto Moerbeek .
--- /dev/null
+++ usr.bin/dc/bcode.c
@@ -0,0 +1,1748 @@
+/*	$OpenBSD: bcode.c,v 1.34 2006/01/19 20:06:55 otto Exp $	*/
+/*	$MidnightBSD: src/usr.bin/dc/bcode.c,v 1.1 2007/08/25 18:43:21 archite Exp $ */
+
+/*
+ * Copyright (c) 2003, Otto Moerbeek <otto at drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$MidnightBSD: src/usr.bin/dc/bcode.c,v 1.1 2007/08/25 18:43:21 archite Exp $";
+#endif /* not lint */
+
+#include <openssl/ssl.h>
+#include <err.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "extern.h"
+
+BIGNUM		zero;
+
+/* #define	DEBUGGING */
+
+#define MAX_ARRAY_INDEX		2048
+#define READSTACK_SIZE		8
+
+#define NO_ELSE			-2	/* -1 is EOF */
+#define REG_ARRAY_SIZE_SMALL	(UCHAR_MAX + 1)
+#define REG_ARRAY_SIZE_BIG	(UCHAR_MAX + 1 + USHRT_MAX + 1)
+
+struct bmachine {
+	struct stack		stack;
+	u_int			scale;
+	u_int			obase;
+	u_int			ibase;
+	size_t			readsp;
+	bool			extended_regs;
+	size_t			reg_array_size;
+	struct stack		*reg;
+	volatile sig_atomic_t	interrupted;
+	struct source		*readstack;
+	size_t			readstack_sz;
+};
+
+static struct bmachine	bmachine;
+static void sighandler(int);
+
+static __inline int	readch(void);
+static __inline void	unreadch(void);
+static __inline char	*readline(void);
+static __inline void	src_free(void);
+
+static __inline u_int	max(u_int, u_int);
+static u_long		get_ulong(struct number *);
+
+static __inline void	push_number(struct number *);
+static __inline void	push_string(char *);
+static __inline void	push(struct value *);
+static __inline struct value *tos(void);
+static __inline struct number	*pop_number(void);
+static __inline char	*pop_string(void);
+static __inline void	clear_stack(void);
+static __inline void	print_tos(void);
+static void		pop_print(void);
+static void		pop_printn(void);
+static __inline void	print_stack(void);
+static __inline void	dup(void);
+static void		swap(void);
+static void		drop(void);
+
+static void		get_scale(void);
+static void		set_scale(void);
+static void		get_obase(void);
+static void		set_obase(void);
+static void		get_ibase(void);
+static void		set_ibase(void);
+static void		stackdepth(void);
+static void		push_scale(void);
+static u_int		count_digits(const struct number *);
+static void		num_digits(void);
+static void		to_ascii(void);
+static void		push_line(void);
+static void		comment(void);
+static void		bexec(char *);
+static void		badd(void);
+static void		bsub(void);
+static void		bmul(void);
+static void		bdiv(void);
+static void		bmod(void);
+static void		bdivmod(void);
+static void		bexp(void);
+static bool		bsqrt_stop(const BIGNUM *, const BIGNUM *, u_int *);
+static void		bsqrt(void);
+static void		not(void);
+static void		equal_numbers(void);
+static void		less_numbers(void);
+static void		lesseq_numbers(void);
+static void		equal(void);
+static void		not_equal(void);
+static void		less(void);
+static void		not_less(void);
+static void		greater(void);
+static void		not_greater(void);
+static void		not_compare(void);
+static bool		compare_numbers(enum bcode_compare, struct number *,
+			    struct number *);
+static void		compare(enum bcode_compare);
+static int		readreg(void);
+static void		load(void);
+static void		store(void);
+static void		load_stack(void);
+static void		store_stack(void);
+static void		load_array(void);
+static void		store_array(void);
+static void		nop(void);
+static void		quit(void);
+static void		quitN(void);
+static void		skipN(void);
+static void		skip_until_mark(void);
+static void		parse_number(void);
+static void		unknown(void);
+static void		eval_string(char *);
+static void		eval_line(void);
+static void		eval_tos(void);
+
+
+typedef void		(*opcode_function)(void);
+
+struct jump_entry {
+	u_char		ch;
+	opcode_function	f;
+};
+
+static opcode_function jump_table[UCHAR_MAX];
+
+static const struct jump_entry jump_table_data[] = {
+	{ ' ',	nop		},
+	{ '!',	not_compare	},
+	{ '#',	comment		},
+	{ '%',	bmod		},
+	{ '(',	less_numbers	},
+	{ '*',	bmul		},
+	{ '+',	badd		},
+	{ '-',	bsub		},
+	{ '.',	parse_number	},
+	{ '/',	bdiv		},
+	{ '0',	parse_number	},
+	{ '1',	parse_number	},
+	{ '2',	parse_number	},
+	{ '3',	parse_number	},
+	{ '4',	parse_number	},
+	{ '5',	parse_number	},
+	{ '6',	parse_number	},
+	{ '7',	parse_number	},
+	{ '8',	parse_number	},
+	{ '9',	parse_number	},
+	{ ':',	store_array	},
+	{ ';',	load_array	},
+	{ '<',	less		},
+	{ '=',	equal		},
+	{ '>',	greater		},
+	{ '?',	eval_line	},
+	{ 'A',	parse_number	},
+	{ 'B',	parse_number	},
+	{ 'C',	parse_number	},
+	{ 'D',	parse_number	},
+	{ 'E',	parse_number	},
+	{ 'F',	parse_number	},
+	{ 'G',	equal_numbers	},
+	{ 'I',	get_ibase	},
+	{ 'J',	skipN		},
+	{ 'K',	get_scale	},
+	{ 'L',	load_stack	},
+	{ 'M',	nop		},
+	{ 'N',	not		},
+	{ 'O',	get_obase	},
+	{ 'P',	pop_print	},
+	{ 'Q',	quitN		},
+	{ 'R',	drop		},
+	{ 'S',	store_stack	},
+	{ 'X',	push_scale	},
+	{ 'Z',	num_digits	},
+	{ '[',	push_line	},
+	{ '\f',	nop		},
+	{ '\n',	nop		},
+	{ '\r',	nop		},
+	{ '\t',	nop		},
+	{ '^',	bexp		},
+	{ '_',	parse_number	},
+	{ 'a',	to_ascii	},
+	{ 'c',	clear_stack	},
+	{ 'd',	dup		},
+	{ 'f',	print_stack	},
+	{ 'i',	set_ibase	},
+	{ 'k',	set_scale	},
+	{ 'l',	load		},
+	{ 'n',	pop_printn	},
+	{ 'o',	set_obase	},
+	{ 'p',	print_tos	},
+	{ 'q',	quit		},
+	{ 'r',	swap		},
+	{ 's',	store		},
+	{ 'v',	bsqrt		},
+	{ 'x',	eval_tos	},
+	{ 'z',	stackdepth	},
+	{ '{',	lesseq_numbers	},
+	{ '~',	bdivmod		}
+};
+
+#define JUMP_TABLE_DATA_SIZE \
+	(sizeof(jump_table_data)/sizeof(jump_table_data[0]))
+
+/* ARGSUSED */
+static void
+sighandler(int ignored)
+{
+	bmachine.interrupted = true;
+}
+
+void
+init_bmachine(bool extended_registers)
+{
+	int i;
+
+	bmachine.extended_regs = extended_registers;
+	bmachine.reg_array_size = bmachine.extended_regs ?
+	    REG_ARRAY_SIZE_BIG : REG_ARRAY_SIZE_SMALL;
+
+	bmachine.reg = malloc(bmachine.reg_array_size *
+	    sizeof(bmachine.reg[0]));
+	if (bmachine.reg == NULL)
+		err(1, NULL);
+
+	for (i = 0; i < UCHAR_MAX; i++)
+		jump_table[i] = unknown;
+	for (i = 0; i < JUMP_TABLE_DATA_SIZE; i++)
+		jump_table[jump_table_data[i].ch] = jump_table_data[i].f;
+
+	stack_init(&bmachine.stack);
+
+	for (i = 0; i < bmachine.reg_array_size; i++)
+		stack_init(&bmachine.reg[i]);
+
+	bmachine.readstack_sz = READSTACK_SIZE;
+	bmachine.readstack = malloc(sizeof(struct source) *
+	    bmachine.readstack_sz);
+	if (bmachine.readstack == NULL)
+		err(1, NULL);
+	bmachine.obase = bmachine.ibase = 10;
+	BN_init(&zero);
+	bn_check(BN_zero(&zero));
+	(void)signal(SIGINT, sighandler);
+}
+
+/* Reset the things needed before processing a (new) file */
+void
+reset_bmachine(struct source *src)
+{
+	bmachine.readsp = 0;
+	bmachine.readstack[0] = *src;
+}
+
+static __inline int
+readch(void)
+{
+	struct source *src = &bmachine.readstack[bmachine.readsp];
+
+	return src->vtable->readchar(src);
+}
+
+static __inline void
+unreadch(void)
+{
+	struct source *src = &bmachine.readstack[bmachine.readsp];
+
+	src->vtable->unreadchar(src);
+}
+
+static __inline char *
+readline(void)
+{
+	struct source *src = &bmachine.readstack[bmachine.readsp];
+
+	return src->vtable->readline(src);
+}
+
+static __inline void
+src_free(void)
+{
+	struct source *src = &bmachine.readstack[bmachine.readsp];
+
+	src->vtable->free(src);
+}
+
+#ifdef DEBUGGING
+void
+pn(const char *str, const struct number *n)
+{
+	char *p = BN_bn2dec(n->number);
+	if (p == NULL)
+		err(1, "BN_bn2dec failed");
+	(void)fputs(str, stderr);
+	(void)fprintf(stderr, " %s (%u)\n" , p, n->scale);
+	OPENSSL_free(p);
+}
+
+void
+pbn(const char *str, const BIGNUM *n)
+{
+	char *p = BN_bn2dec(n);
+	if (p == NULL)
+		err(1, "BN_bn2dec failed");
+	(void)fputs(str, stderr);
+	(void)fprintf(stderr, " %s\n", p);
+	OPENSSL_free(p);
+}
+
+#endif
+
+static __inline u_int
+max(u_int a, u_int b)
+{
+	return a > b ? a : b;
+}
+
+static unsigned long factors[] = {
+	0, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
+	100000000, 1000000000
+};
+
+void
+scale_number(BIGNUM *n, int s)
+{
+	int abs_scale;
+
+	if (s == 0)
+		return;
+
+	abs_scale = s > 0 ? s : -s;
+
+	if (abs_scale < sizeof(factors)/sizeof(factors[0])) {
+		if (s > 0)
+			bn_check(BN_mul_word(n, factors[abs_scale]));
+		else
+			(void)BN_div_word(n, factors[abs_scale]);
+	} else {
+		BIGNUM *a, *p;
+		BN_CTX *ctx;
+
+		a = BN_new();
+		bn_checkp(a);
+		p = BN_new();
+		bn_checkp(p);
+		ctx = BN_CTX_new();
+		bn_checkp(ctx);
+
+		bn_check(BN_set_word(a, 10));
+		bn_check(BN_set_word(p, abs_scale));
+		bn_check(BN_exp(a, a, p, ctx));
+		if (s > 0)
+			bn_check(BN_mul(n, n, a, ctx));
+		else
+			bn_check(BN_div(n, NULL, n, a, ctx));
+		BN_CTX_free(ctx);
+		BN_free(a);
+		BN_free(p);
+	}
+}
+
+void
+split_number(const struct number *n, BIGNUM *i, BIGNUM *f)
+{
+	u_long rem;
+
+	bn_checkp(BN_copy(i, n->number));
+
+	if (n->scale == 0 && f != NULL)
+		bn_check(BN_zero(f));
+	else if (n->scale < sizeof(factors)/sizeof(factors[0])) {
+		rem = BN_div_word(i, factors[n->scale]);
+		if (f != NULL)
+			bn_check(BN_set_word(f, rem));
+	} else {
+		BIGNUM *a, *p;
+		BN_CTX *ctx;
+
+		a = BN_new();
+		bn_checkp(a);
+		p = BN_new();
+		bn_checkp(p);
+		ctx = BN_CTX_new();
+		bn_checkp(ctx);
+
+		bn_check(BN_set_word(a, 10));
+		bn_check(BN_set_word(p, n->scale));
+		bn_check(BN_exp(a, a, p, ctx));
+		bn_check(BN_div(i, f, n->number, a, ctx));
+		BN_CTX_free(ctx);
+		BN_free(a);
+		BN_free(p);
+	}
+}
+
+__inline void
+normalize(struct number *n, u_int s)
+{
+	scale_number(n->number, s - n->scale);
+	n->scale = s;
+}
+
+static u_long
+get_ulong(struct number *n)
+{
+	normalize(n, 0);
+	return BN_get_word(n->number);
+}
+
+void
+negate(struct number *n)
+{
+	bn_check(BN_sub(n->number, &zero, n->number));
+}
+
+static __inline void
+push_number(struct number *n)
+{
+	stack_pushnumber(&bmachine.stack, n);
+}
+
+static __inline void
+push_string(char *string)
+{
+	stack_pushstring(&bmachine.stack, string);
+}
+
+static __inline void
+push(struct value *v)
+{
+	stack_push(&bmachine.stack, v);
+}
+
+static __inline struct value *
+tos(void)
+{
+	return stack_tos(&bmachine.stack);
+}
+
+static __inline struct value *
+pop(void)
+{
+	return stack_pop(&bmachine.stack);
+}
+
+static __inline struct number *
+pop_number(void)
+{
+	return stack_popnumber(&bmachine.stack);
+}
+
+static __inline char *
+pop_string(void)
+{
+	return stack_popstring(&bmachine.stack);
+}
+
+static __inline void
+clear_stack(void)
+{
+	stack_clear(&bmachine.stack);
+}
+
+static __inline void
+print_stack(void)
+{
+	stack_print(stdout, &bmachine.stack, "", bmachine.obase);
+}
+
+static __inline void
+print_tos(void)
+{
+	struct value *value = tos();
+	if (value != NULL) {
+		print_value(stdout, value, "", bmachine.obase);
+		(void)putchar('\n');
+	}
+	else
+		warnx("stack empty");
+}
+
+static void
+pop_print(void)
+{
+	struct value *value = pop();
+
+	if (value != NULL) {
+		switch (value->type) {
+		case BCODE_NONE:
+			break;
+		case BCODE_NUMBER:
+			normalize(value->u.num, 0);
+			print_ascii(stdout, value->u.num);
+			(void)fflush(stdout);
+			break;
+		case BCODE_STRING:
+			(void)fputs(value->u.string, stdout);
+			(void)fflush(stdout);
+			break;
+		}
+		stack_free_value(value);
+	}
+}
+
+static void
+pop_printn(void)
+{
+	struct value *value = pop();
+
+	if (value != NULL) {
+		print_value(stdout, value, "", bmachine.obase);
+		(void)fflush(stdout);
+		stack_free_value(value);
+	}
+}
+
+static __inline void
+dup(void)
+{
+	stack_dup(&bmachine.stack);
+}
+
+static void
+swap(void)
+{
+	stack_swap(&bmachine.stack);
+}
+
+static void
+drop(void)
+{
+	struct value *v = pop();
+	if (v != NULL)
+		stack_free_value(v);
+}
+
+static void
+get_scale(void)
+{
+	struct number	*n;
+
+	n = new_number();
+	bn_check(BN_set_word(n->number, bmachine.scale));
+	push_number(n);
+}
+
+static void
+set_scale(void)
+{
+	struct number	*n;
+	u_long		scale;
+
+	n = pop_number();
+	if (n != NULL) {
+		if (BN_cmp(n->number, &zero) < 0)
+			warnx("scale must be a nonnegative number");
+		else {
+			scale = get_ulong(n);
+			if (scale != BN_MASK2 && scale <= UINT_MAX)
+				bmachine.scale = (u_int)scale;
+			else
+				warnx("scale too large");
+			}
+		free_number(n);
+	}
+}
+
+static void
+get_obase(void)
+{
+	struct number	*n;
+
+	n = new_number();
+	bn_check(BN_set_word(n->number, bmachine.obase));
+	push_number(n);
+}
+
+static void
+set_obase(void)
+{
+	struct number	*n;
+	u_long		base;
+
+	n = pop_number();
+	if (n != NULL) {
+		base = get_ulong(n);
+		if (base != BN_MASK2 && base > 1 && base <= UINT_MAX)
+			bmachine.obase = (u_int)base;
+		else
+			warnx("output base must be a number greater than 1");
+		free_number(n);
+	}
+}
+
+static void
+get_ibase(void)
+{
+	struct number *n;
+
+	n = new_number();
+	bn_check(BN_set_word(n->number, bmachine.ibase));
+	push_number(n);
+}
+
+static void
+set_ibase(void)
+{
+	struct number	*n;
+	u_long		base;
+
+	n = pop_number();
+	if (n != NULL) {
+		base = get_ulong(n);
+		if (base != BN_MASK2 && 2 <= base && base <= 16)
+			bmachine.ibase = (u_int)base;
+		else
+			warnx("input base must be a number between 2 and 16 "
+			    "(inclusive)");
+		free_number(n);
+	}
+}
+
+static void
+stackdepth(void)
+{
+	size_t i;
+	struct number *n;
+
+	i = stack_size(&bmachine.stack);
+	n = new_number();
+	bn_check(BN_set_word(n->number, i));
+	push_number(n);
+}
+
+static void
+push_scale(void)
+{
+	struct value	*value;
+	u_int		scale = 0;
+	struct number	*n;
+
+
+	value = pop();
+	if (value != NULL) {
+		switch (value->type) {
+		case BCODE_NONE:
+			return;
+		case BCODE_NUMBER:
+			scale = value->u.num->scale;
+			break;
+		case BCODE_STRING:
+			break;
+		}
+		stack_free_value(value);
+		n = new_number();
+		bn_check(BN_set_word(n->number, scale));
+		push_number(n);
+	}
+}
+
+static u_int
+count_digits(const struct number *n)
+{
+	struct number	*int_part, *fract_part;
+	u_int		i;
+
+	if (BN_is_zero(n->number))
+		return 1;
+
+	int_part = new_number();
+	fract_part = new_number();
+	fract_part->scale = n->scale;
+	split_number(n, int_part->number, fract_part->number);
+
+	i = 0;
+	while (!BN_is_zero(int_part->number)) {
+		(void)BN_div_word(int_part->number, 10);
+		i++;
+	}
+	free_number(int_part);
+	free_number(fract_part);
+	return i + n->scale;
+}
+
+static void
+num_digits(void)
+{
+	struct value	*value;
+	size_t		digits;
+	struct number	*n = NULL;
+
+	value = pop();
+	if (value != NULL) {
+		switch (value->type) {
+		case BCODE_NONE:
+			return;
+		case BCODE_NUMBER:
+			digits = count_digits(value->u.num);
+			n = new_number();
+			bn_check(BN_set_word(n->number, digits));
+			break;
+		case BCODE_STRING:
+			digits = strlen(value->u.string);
+			n = new_number();
+			bn_check(BN_set_word(n->number, digits));
+			break;
+		}
+		stack_free_value(value);
+		push_number(n);
+	}
+}
+
+static void
+to_ascii(void)
+{
+	char		str[2];
+	struct value	*value;
+	struct number	*n;
+
+	value = pop();
+	if (value != NULL) {
+		str[1] = '\0';
+		switch (value->type) {
+		case BCODE_NONE:
+			return;
+		case BCODE_NUMBER:
+			n = value->u.num;
+			normalize(n, 0);
+			if (BN_num_bits(n->number) > 8)
+				bn_check(BN_mask_bits(n->number, 8));
+			str[0] = (char)BN_get_word(n->number);
+			break;
+		case BCODE_STRING:
+			str[0] = value->u.string[0];
+			break;
+		}
+		stack_free_value(value);
+		push_string(bstrdup(str));
+	}
+}
+
+static int
+readreg(void)
+{
+	int idx, ch1, ch2;
+
+	idx = readch();
+	if (idx == 0xff && bmachine.extended_regs) {
+		ch1 = readch();
+		ch2 = readch();
+		if (ch1 == EOF || ch2 == EOF) {
+			warnx("unexpected eof");
+			idx = -1;
+		} else
+			idx = (ch1 << 8) + ch2 + UCHAR_MAX + 1;
+	}
+	if (idx < 0 || idx >= bmachine.reg_array_size) {
+		warnx("internal error: reg num = %d", idx);
+		idx = -1;
+	}
+	return idx;
+}
+
+static void
+load(void)
+{
+	int		idx;
+	struct value	*v, copy;
+	struct number	*n;
+
+	idx = readreg();
+	if (idx >= 0) {
+		v = stack_tos(&bmachine.reg[idx]);
+		if (v == NULL) {
+			n = new_number();
+			bn_check(BN_zero(n->number));
+			push_number(n);
+		} else
+			push(stack_dup_value(v, &copy));
+	}
+}
+
+static void
+store(void)
+{
+	int		idx;
+	struct value	*val;
+
+	idx = readreg();
+	if (idx >= 0) {
+		val = pop();
+		if (val == NULL) {
+			return;
+		}
+		stack_set_tos(&bmachine.reg[idx], val);
+	}
+}
+
+static void
+load_stack(void)
+{
+	int		idx;
+	struct stack	*stack;
+	struct value	*value, copy;
+
+	idx = readreg();
+	if (idx >= 0) {
+		stack = &bmachine.reg[idx];
+		value = NULL;
+		if (stack_size(stack) > 0) {
+			value = stack_pop(stack);
+		}
+		if (value != NULL)
+			push(stack_dup_value(value, &copy));
+		else
+			warnx("stack register '%c' (0%o) is empty",
+			    idx, idx);
+	}
+}
+
+static void
+store_stack(void)
+{
+	int		idx;
+	struct value	*value;
+
+	idx = readreg();
+	if (idx >= 0) {
+		value = pop();
+		if (value == NULL)
+			return;
+		stack_push(&bmachine.reg[idx], value);
+	}
+}
+
+static void
+load_array(void)
+{
+	int			reg;
+	struct number		*inumber, *n;
+	u_long			idx;
+	struct stack		*stack;
+	struct value		*v, copy;
+
+	reg = readreg();
+	if (reg >= 0) {
+		inumber = pop_number();
+		if (inumber == NULL)
+			return;
+		idx = get_ulong(inumber);
+		if (BN_cmp(inumber->number, &zero) < 0)
+			warnx("negative idx");
+		else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX)
+			warnx("idx too big");
+		else {
+			stack = &bmachine.reg[reg];
+			v = frame_retrieve(stack, idx);
+			if (v == NULL) {
+				n = new_number();
+				bn_check(BN_zero(n->number));
+				push_number(n);
+			}
+			else
+				push(stack_dup_value(v, &copy));
+		}
+		free_number(inumber);
+	}
+}
+
+static void
+store_array(void)
+{
+	int			reg;
+	struct number		*inumber;
+	u_long			idx;
+	struct value		*value;
+	struct stack		*stack;
+
+	reg = readreg();
+	if (reg >= 0) {
+		inumber = pop_number();
+		if (inumber == NULL)
+			return;
+		value = pop();
+		if (value == NULL) {
+			free_number(inumber);
+			return;
+		}
+		idx = get_ulong(inumber);
+		if (BN_cmp(inumber->number, &zero) < 0) {
+			warnx("negative idx");
+			stack_free_value(value);
+		} else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX) {
+			warnx("idx too big");
+			stack_free_value(value);
+		} else {
+			stack = &bmachine.reg[reg];
+			frame_assign(stack, idx, value);
+		}
+		free_number(inumber);
+	}
+}
+
+static void
+push_line(void)
+{
+	push_string(read_string(&bmachine.readstack[bmachine.readsp]));
+}
+
+static void
+comment(void)
+{
+	free(readline());
+}
+
+static void
+bexec(char *line)
+{
+	(void)system(line);
+	free(line);
+}
+
+static void
+badd(void)
+{
+	struct number	*a, *b;
+	struct number	*r;
+
+	a = pop_number();
+	if (a == NULL) {
+		return;
+	}
+	b = pop_number();
+	if (b == NULL) {
+		push_number(a);
+		return;
+	}
+
+	r = new_number();
+	r->scale = max(a->scale, b->scale);
+	if (r->scale > a->scale)
+		normalize(a, r->scale);
+	else if (r->scale > b->scale)
+		normalize(b, r->scale);
+	bn_check(BN_add(r->number, a->number, b->number));
+	push_number(r);
+	free_number(a);
+	free_number(b);
+}
+
+static void
+bsub(void)
+{
+	struct number	*a, *b;
+	struct number	*r;
+
+	a = pop_number();
+	if (a == NULL) {
+		return;
+	}
+	b = pop_number();
+	if (b == NULL) {
+		push_number(a);
+		return;
+	}
+
+	r = new_number();
+
+	r->scale = max(a->scale, b->scale);
+	if (r->scale > a->scale)
+		normalize(a, r->scale);
+	else if (r->scale > b->scale)
+		normalize(b, r->scale);
+	bn_check(BN_sub(r->number, b->number, a->number));
+	push_number(r);
+	free_number(a);
+	free_number(b);
+}
+
+void
+bmul_number(struct number *r, struct number *a, struct number *b)
+{
+	BN_CTX		*ctx;
+
+	/* Create copies of the scales, since r might be equal to a or b */
+	u_int ascale = a->scale;
+	u_int bscale = b->scale;
+	u_int rscale = ascale + bscale;
+
+	ctx = BN_CTX_new();
+	bn_checkp(ctx);
+	bn_check(BN_mul(r->number, a->number, b->number, ctx));
+	BN_CTX_free(ctx);
+
+	if (rscale > bmachine.scale && rscale > ascale && rscale > bscale) {
+		r->scale = rscale;
+		normalize(r, max(bmachine.scale, max(ascale, bscale)));
+	} else
+		r->scale = rscale;
+}
+
+static void
+bmul(void)
+{
+	struct number	*a, *b;
+	struct number	*r;
+
+	a = pop_number();
+	if (a == NULL) {
+		return;
+	}
+	b = pop_number();
+	if (b == NULL) {
+		push_number(a);
+		return;
+	}
+
+	r = new_number();
+	bmul_number(r, a, b);
+
+	push_number(r);
+	free_number(a);
+	free_number(b);
+}
+
+static void
+bdiv(void)
+{
+	struct number	*a, *b;
+	struct number	*r;
+	u_int		scale;
+	BN_CTX		*ctx;
+
+	a = pop_number();
+	if (a == NULL) {
+		return;
+	}
+	b = pop_number();
+	if (b == NULL) {
+		push_number(a);
+		return;
+	}
+
+	r = new_number();
+	r->scale = bmachine.scale;
+	scale = max(a->scale, b->scale);
+
+	if (BN_is_zero(a->number))
+		warnx("divide by zero");
+	else {
+		normalize(a, scale);
+		normalize(b, scale + r->scale);
+
+		ctx = BN_CTX_new();
+		bn_checkp(ctx);
+		bn_check(BN_div(r->number, NULL, b->number, a->number, ctx));
+		BN_CTX_free(ctx);
+	}
+	push_number(r);
+	free_number(a);
+	free_number(b);
+}
+
+static void
+bmod(void)
+{
+	struct number	*a, *b;
+	struct number	*r;
+	u_int		scale;
+	BN_CTX		*ctx;
+
+	a = pop_number();
+	if (a == NULL) {
+		return;
+	}
+	b = pop_number();
+	if (b == NULL) {
+		push_number(a);
+		return;
+	}
+
+	r = new_number();
+	scale = max(a->scale, b->scale);
+	r->scale = max(b->scale, a->scale + bmachine.scale);
+
+	if (BN_is_zero(a->number))
+		warnx("remainder by zero");
+	else {
+		normalize(a, scale);
+		normalize(b, scale + bmachine.scale);
+
+		ctx = BN_CTX_new();
+		bn_checkp(ctx);
+		bn_check(BN_mod(r->number, b->number, a->number, ctx));
+		BN_CTX_free(ctx);
+	}
+	push_number(r);
+	free_number(a);
+	free_number(b);
+}
+
+static void
+bdivmod(void)
+{
+	struct number	*a, *b;
+	struct number	*rdiv, *rmod;
+	u_int		scale;
+	BN_CTX		*ctx;
+
+	a = pop_number();
+	if (a == NULL) {
+		return;
+	}
+	b = pop_number();
+	if (b == NULL) {
+		push_number(a);
+		return;
+	}
+
+	rdiv = new_number();
+	rmod = new_number();
+	rdiv->scale = bmachine.scale;
+	rmod->scale = max(b->scale, a->scale + bmachine.scale);
+	scale = max(a->scale, b->scale);
+
+	if (BN_is_zero(a->number))
+		warnx("divide by zero");
+	else {
+		normalize(a, scale);
+		normalize(b, scale + bmachine.scale);
+
+		ctx = BN_CTX_new();
+		bn_checkp(ctx);
+		bn_check(BN_div(rdiv->number, rmod->number,
+		    b->number, a->number, ctx));
+		BN_CTX_free(ctx);
+	}
+	push_number(rdiv);
+	push_number(rmod);
+	free_number(a);
+	free_number(b);
+}
+
+static void
+bexp(void)
+{
+	struct number	*a, *p;
+	struct number	*r;
+	bool		neg;
+	u_int		scale;
+
+	p = pop_number();
+	if (p == NULL) {
+		return;
+	}
+	a = pop_number();
+	if (a == NULL) {
+		push_number(p);
+		return;
+	}
+
+	if (p->scale != 0)
+		warnx("Runtime warning: non-zero scale in exponent");
+	normalize(p, 0);
+
+	neg = false;
+	if (BN_cmp(p->number, &zero) < 0) {
+		neg = true;
+		negate(p);
+		scale = bmachine.scale;
+	} else {
+		/* Posix bc says min(a.scale * b, max(a.scale, scale) */
+		u_long	b;
+		u_int	m;
+
+		b = BN_get_word(p->number);
+		m = max(a->scale, bmachine.scale);
+		scale = a->scale * (u_int)b;
+		if (scale > m || (a->scale > 0 && (b == BN_MASK2 ||
+		    b > UINT_MAX)))
+			scale = m;
+	}
+
+	if (BN_is_zero(p->number)) {
+		r = new_number();
+		bn_check(BN_one(r->number));
+		normalize(r, scale);
+	} else {
+		while (!BN_is_bit_set(p->number, 0)) {
+			bmul_number(a, a, a);
+			bn_check(BN_rshift1(p->number, p->number));
+		}
+
+		r = dup_number(a);
+		normalize(r, scale);
+		bn_check(BN_rshift1(p->number, p->number));
+
+		while (!BN_is_zero(p->number)) {
+			bmul_number(a, a, a);
+			if (BN_is_bit_set(p->number, 0))
+				bmul_number(r, r, a);
+			bn_check(BN_rshift1(p->number, p->number));
+		}
+
+		if (neg) {
+			BN_CTX	*ctx;
+			BIGNUM	*one;
+
+			one = BN_new();
+			bn_checkp(one);
+			bn_check(BN_one(one));
+			ctx = BN_CTX_new();
+			bn_checkp(ctx);
+			scale_number(one, r->scale + scale);
+			normalize(r, scale);
+			bn_check(BN_div(r->number, NULL, one, r->number, ctx));
+			BN_free(one);
+			BN_CTX_free(ctx);
+		} else
+			normalize(r, scale);
+	}
+	push_number(r);
+	free_number(a);
+	free_number(p);
+}
+
+static bool
+bsqrt_stop(const BIGNUM *x, const BIGNUM *y, u_int *onecount)
+{
+	BIGNUM *r;
+	bool ret;
+
+	r = BN_new();
+	bn_checkp(r);
+	bn_check(BN_sub(r, x, y));
+	if (BN_is_one(r))
+		(*onecount)++;
+	ret = BN_is_zero(r);
+	BN_free(r);
+	return ret || *onecount > 1;
+}
+
+static void
+bsqrt(void)
+{
+	struct number	*n;
+	struct number	*r;
+	BIGNUM		*x, *y;
+	u_int		scale, onecount;
+	BN_CTX		*ctx;
+
+	onecount = 0;
+	n = pop_number();
+	if (n == NULL) {
+		return;
+	}
+	if (BN_is_zero(n->number)) {
+		r = new_number();
+		push_number(r);
+	} else if (BN_cmp(n->number, &zero) < 0)
+		warnx("square root of negative number");
+	else {
+		scale = max(bmachine.scale, n->scale);
+		normalize(n, 2*scale);
+		x = BN_dup(n->number);
+		bn_checkp(x);
+		bn_check(BN_rshift(x, x, BN_num_bits(x)/2));
+		y = BN_new();
+		bn_checkp(y);
+		ctx = BN_CTX_new();
+		bn_checkp(ctx);
+		for (;;) {
+			bn_checkp(BN_copy(y, x));
+			bn_check(BN_div(x, NULL, n->number, x, ctx));
+			bn_check(BN_add(x, x, y));
+			bn_check(BN_rshift1(x, x));
+			if (bsqrt_stop(x, y, &onecount))
+				break;
+		}
+		r = bmalloc(sizeof(*r));
+		r->scale = scale;
+		r->number = y;
+		BN_free(x);
+		BN_CTX_free(ctx);
+		push_number(r);
+	}
+
+	free_number(n);
+}
+
+static void
+not(void)
+{
+	struct number	*a;
+
+	a = pop_number();
+	if (a == NULL) {
+		return;
+	}
+	a->scale = 0;
+	bn_check(BN_set_word(a->number, BN_get_word(a->number) ? 0 : 1));
+	push_number(a);
+}
+
+static void
+equal(void)
+{
+	compare(BCODE_EQUAL);
+}
+
+static void
+equal_numbers(void)
+{
+	struct number *a, *b, *r;
+
+	a = pop_number();
+	if (a == NULL) {
+		return;
+	}
+	b = pop_number();
+	if (b == NULL) {
+		push_number(a);
+		return;
+	}
+	r = new_number();
+	bn_check(BN_set_word(r->number,
+	    compare_numbers(BCODE_EQUAL, a, b) ? 1 : 0));
+	push_number(r);
+}
+
+static void
+less_numbers(void)
+{
+	struct number *a, *b, *r;
+
+	a = pop_number();
+	if (a == NULL) {
+		return;
+	}
+	b = pop_number();
+	if (b == NULL) {
+		push_number(a);
+		return;
+	}
+	r = new_number();
+	bn_check(BN_set_word(r->number,
+	    compare_numbers(BCODE_LESS, a, b) ? 1 : 0));
+	push_number(r);
+}
+
+static void
+lesseq_numbers(void)
+{
+	struct number *a, *b, *r;
+
+	a = pop_number();
+	if (a == NULL) {
+		return;
+	}
+	b = pop_number();
+	if (b == NULL) {
+		push_number(a);
+		return;
+	}
+	r = new_number();
+	bn_check(BN_set_word(r->number,
+	    compare_numbers(BCODE_NOT_GREATER, a, b) ? 1 : 0));
+	push_number(r);
+}
+
+static void
+not_equal(void)
+{
+	compare(BCODE_NOT_EQUAL);
+}
+
+static void
+less(void)
+{
+	compare(BCODE_LESS);
+}
+
+static void
+not_compare(void)
+{
+	switch (readch()) {
+	case '<':
+		not_less();
+		break;
+	case '>':
+		not_greater();
+		break;
+	case '=':
+		not_equal();
+		break;
+	default:
+		unreadch();
+		bexec(readline());
+		break;
+	}
+}
+
+static void
+not_less(void)
+{
+	compare(BCODE_NOT_LESS);
+}
+
+static void
+greater(void)
+{
+	compare(BCODE_GREATER);
+}
+
+static void
+not_greater(void)
+{
+	compare(BCODE_NOT_GREATER);
+}
+
+static bool
+compare_numbers(enum bcode_compare type, struct number *a, struct number *b)
+{
+	u_int	scale;
+	int	cmp;
+
+	scale = max(a->scale, b->scale);
+
+	if (scale > a->scale)
+		normalize(a, scale);
+	else if (scale > b->scale)
+		normalize(b, scale);
+
+	cmp = BN_cmp(a->number, b->number);
+
+	free_number(a);
+	free_number(b);
+
+	switch (type) {
+	case BCODE_EQUAL:
+		return cmp == 0;
+	case BCODE_NOT_EQUAL:
+		return cmp != 0;
+	case BCODE_LESS:
+		return cmp < 0;
+	case BCODE_NOT_LESS:
+		return cmp >= 0;
+	case BCODE_GREATER:
+		return cmp > 0;
+	case BCODE_NOT_GREATER:
+		return cmp <= 0;
+	}
+	return false;
+}
+
+static void
+compare(enum bcode_compare type)
+{
+	int		idx, elseidx;
+	struct number	*a, *b;
+	bool		ok;
+	struct value	*v;
+
+	elseidx = NO_ELSE;
+	idx = readreg();
+	if (readch() == 'e')
+		elseidx = readreg();
+	else
+		unreadch();
+
+	a = pop_number();
+	if (a == NULL)
+		return;
+	b = pop_number();
+	if (b == NULL) {
+		push_number(a);
+		return;
+	}
+
+	ok = compare_numbers(type, a, b);
+
+	if (!ok && elseidx != NO_ELSE)
+		idx = elseidx;
+
+	if (idx >= 0 && (ok || (!ok && elseidx != NO_ELSE))) {
+		v = stack_tos(&bmachine.reg[idx]);
+		if (v == NULL)
+			warnx("register '%c' (0%o) is empty", idx, idx);
+		else {
+			switch(v->type) {
+			case BCODE_NONE:
+				warnx("register '%c' (0%o) is empty", idx, idx);
+				break;
+			case BCODE_NUMBER:
+				warn("eval called with non-string argument");
+				break;
+			case BCODE_STRING:
+				eval_string(bstrdup(v->u.string));
+				break;
+			}
+		}
+	}
+}
+
+
+static void
+nop(void)
+{
+}
+
+static void
+quit(void)
+{
+	if (bmachine.readsp < 2)
+		exit(0);
+	src_free();
+	bmachine.readsp--;
+	src_free();
+	bmachine.readsp--;
+}
+
+static void
+quitN(void)
+{
+	struct number	*n;
+	u_long		i;
+
+	n = pop_number();
+	if (n == NULL)
+		return;
+	i = get_ulong(n);
+	if (i == BN_MASK2 || i == 0)
+		warnx("Q command requires a number >= 1");
+	else if (bmachine.readsp < i)
+		warnx("Q command argument exceeded string execution depth");
+	else {
+		while (i-- > 0) {
+			src_free();
+			bmachine.readsp--;
+		}
+	}
+}
+
+static void
+skipN(void)
+{
+	struct number	*n;
+	u_long		i;
+
+	n = pop_number();
+	if (n == NULL)
+		return;
+	i = get_ulong(n);
+	if (i == BN_MASK2)
+		warnx("J command requires a number >= 0");
+	else if (i > 0 && bmachine.readsp < i)
+		warnx("J command argument exceeded string execution depth");
+	else {
+		while (i-- > 0) {
+			src_free();
+			bmachine.readsp--;
+		}
+		skip_until_mark();
+	}
+}
+
+static void
+skip_until_mark(void)
+{
+	int ch;
+
+	for (;;) {
+		ch = readch();
+		switch (ch) {
+		case 'M':
+			return;
+		case EOF:
+			errx(1, "mark not found");
+			return;
+		case 'l':
+		case 'L':
+		case 's':
+		case 'S':
+		case ':':
+		case ';':
+		case '<':
+		case '>':
+		case '=':
+			(void)readreg();
+			if (readch() == 'e')
+				(void)readreg();
+			else
+				unreadch();
+			break;
+		case '[':
+			free(read_string(&bmachine.readstack[bmachine.readsp]));
+			break;
+		case '!':
+			switch (ch = readch()) {
+				case '<':
+				case '>':
+				case '=':
+					(void)readreg();
+					if (readch() == 'e')
+						(void)readreg();
+					else
+						unreadch();
+					break;
+				default:
+					free(readline());
+					break;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static void
+parse_number(void)
+{
+	unreadch();
+	push_number(readnumber(&bmachine.readstack[bmachine.readsp],
+	    bmachine.ibase));
+}
+
+static void
+unknown(void)
+{
+	int ch = bmachine.readstack[bmachine.readsp].lastchar;
+	warnx("%c (0%o) is unimplemented", ch, ch);
+}
+
+static void
+eval_string(char *p)
+{
+	int ch;
+
+	if (bmachine.readsp > 0) {
+		/* Check for tail call. Do not recurse in that case. */
+		ch = readch();
+		if (ch == EOF) {
+			src_free();
+			src_setstring(&bmachine.readstack[bmachine.readsp], p);
+			return;
+		} else
+			unreadch();
+	}
+	if (bmachine.readsp == bmachine.readstack_sz - 1) {
+		size_t newsz = bmachine.readstack_sz * 2;
+		struct source *stack;
+		stack = realloc(bmachine.readstack, newsz *
+		    sizeof(struct source));
+		if (stack == NULL)
+			err(1, "recursion too deep");
+		bmachine.readstack_sz = newsz;
+		bmachine.readstack = stack;
+	}
+	src_setstring(&bmachine.readstack[++bmachine.readsp], p);
+}
+
+static void
+eval_line(void)
+{
+	/* Always read from stdin */
+	struct source	in;
+	char		*p;
+
+	src_setstream(&in, stdin);
+	p = (*in.vtable->readline)(&in);
+	eval_string(p);
+}
+
+static void
+eval_tos(void)
+{
+	char *p;
+
+	p = pop_string();
+	if (p == NULL)
+		return;
+	eval_string(p);
+}
+
+void
+eval(void)
+{
+	int	ch;
+
+	for (;;) {
+		ch = readch();
+		if (ch == EOF) {
+			if (bmachine.readsp == 0)
+				return;
+			src_free();
+			bmachine.readsp--;
+			continue;
+		}
+		if (bmachine.interrupted) {
+			if (bmachine.readsp > 0) {
+				src_free();
+				bmachine.readsp--;
+				continue;
+			} else
+				bmachine.interrupted = false;
+		}
+#ifdef DEBUGGING
+		(void)fprintf(stderr, "# %c\n", ch);
+		stack_print(stderr, &bmachine.stack, "* ",
+		    bmachine.obase);
+		(void)fprintf(stderr, "%d =>\n", bmachine.readsp);
+#endif
+
+		if (0 <= ch && ch < UCHAR_MAX)
+			(*jump_table[ch])();
+		else
+			warnx("internal error: opcode %d", ch);
+
+#ifdef DEBUGGING
+		stack_print(stderr, &bmachine.stack, "* ",
+		    bmachine.obase);
+		(void)fprintf(stderr, "%d ==\n", bmachine.readsp);
+#endif
+	}
+}
--- /dev/null
+++ usr.bin/dc/stack.c
@@ -0,0 +1,362 @@
+/*	$OpenBSD: stack.c,v 1.9 2006/01/16 08:09:25 otto Exp $	*/
+/*	$MidnightBSD: src/usr.bin/dc/stack.c,v 1.1 2007/08/25 18:43:21 archite Exp $ */
+
+/*
+ * Copyright (c) 2003, Otto Moerbeek <otto at drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$MidnightBSD: src/usr.bin/dc/stack.c,v 1.1 2007/08/25 18:43:21 archite Exp $";
+#endif /* not lint */
+
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "extern.h"
+
+static __inline bool	stack_empty(const struct stack *);
+static void		stack_grow(struct stack *);
+static struct array	*array_new(void);
+static __inline void	array_free(struct array *);
+static struct array *	array_dup(const struct array *);
+static __inline void	array_grow(struct array *, size_t);
+static __inline void	array_assign(struct array *, size_t, const struct value *);
+static __inline struct value	*array_retrieve(const struct array *, size_t);
+
+void
+stack_init(struct stack *stack)
+{
+	stack->size = 0;
+	stack->sp = -1;
+	stack->stack = NULL;
+}
+
+static __inline bool
+stack_empty(const struct stack *stack)
+{
+	bool empty = stack->sp == -1;
+	if (empty)
+		warnx("stack empty");
+	return empty;
+}
+
+/* Clear number or string, but leave value itself */
+void
+stack_free_value(struct value *v)
+{
+	switch (v->type) {
+	case BCODE_NONE:
+		break;
+	case BCODE_NUMBER:
+		free_number(v->u.num);
+		break;
+	case BCODE_STRING:
+		free(v->u.string);
+		break;
+	}
+	if (v->array != NULL) {
+		array_free(v->array);
+		v->array = NULL;
+	}
+}
+
+/* Copy number or string content into already allocated target */
+struct value *
+stack_dup_value(const struct value *a, struct value *copy)
+{
+	copy->type = a->type;
+
+	switch (a->type) {
+	case BCODE_NONE:
+		break;
+	case BCODE_NUMBER:
+		copy->u.num = dup_number(a->u.num);
+		break;
+	case BCODE_STRING:
+		copy->u.string = strdup(a->u.string);
+		if (copy->u.string == NULL)
+			err(1, NULL);
+		break;
+	}
+
+	copy->array = a->array == NULL ? NULL : array_dup(a->array);
+
+	return copy;
+}
+
+size_t
+stack_size(const struct stack *stack)
+{
+	return stack->sp + 1;
+}
+
+void
+stack_dup(struct stack *stack)
+{
+	struct value	*value;
+	struct value	copy;
+
+	value = stack_tos(stack);
+	if (value == NULL) {
+		warnx("stack empty");
+		return;
+	}
+	stack_push(stack, stack_dup_value(value, &copy));
+}
+
+void
+stack_swap(struct stack *stack)
+{
+	struct value	copy;
+
+	if (stack->sp < 1) {
+		warnx("stack empty");
+		return;
+	}
+	copy = stack->stack[stack->sp];
+	stack->stack[stack->sp] = stack->stack[stack->sp-1];
+	stack->stack[stack->sp-1] = copy;
+}
+
+static void
+stack_grow(struct stack *stack)
+{
+	size_t new_size, i;
+
+	if (++stack->sp == stack->size) {
+		new_size = stack->size * 2 + 1;
+		stack->stack = brealloc(stack->stack,
+		    new_size * sizeof(*stack->stack));
+		for (i = stack->size; i < new_size; i++)
+			stack->stack[i].array = NULL;
+		stack->size = new_size;
+	}
+}
+
+void
+stack_pushnumber(struct stack *stack, struct number *b)
+{
+	stack_grow(stack);
+	stack->stack[stack->sp].type = BCODE_NUMBER;
+	stack->stack[stack->sp].u.num = b;
+}
+
+void
+stack_pushstring(struct stack *stack, char *string)
+{
+	stack_grow(stack);
+	stack->stack[stack->sp].type = BCODE_STRING;
+	stack->stack[stack->sp].u.string = string;
+}
+
+void
+stack_push(struct stack *stack, struct value *v)
+{
+	switch (v->type) {
+	case BCODE_NONE:
+		stack_grow(stack);
+		stack->stack[stack->sp].type = BCODE_NONE;
+		break;
+	case BCODE_NUMBER:
+		stack_pushnumber(stack, v->u.num);
+		break;
+	case BCODE_STRING:
+		stack_pushstring(stack, v->u.string);
+		break;
+	}
+	stack->stack[stack->sp].array = v->array == NULL ?
+	    NULL : array_dup(v->array);
+}
+
+struct value *
+stack_tos(const struct stack *stack)
+{
+	if (stack->sp == -1)
+		return NULL;
+	return &stack->stack[stack->sp];
+}
+
+void
+stack_set_tos(struct stack *stack, struct value *v)
+{
+	if (stack->sp == -1)
+		stack_push(stack, v);
+	else {
+		stack_free_value(&stack->stack[stack->sp]);
+		stack->stack[stack->sp] = *v;
+		stack->stack[stack->sp].array = v->array == NULL ?
+		    NULL : array_dup(v->array);
+	}
+}
+
+struct value *
+stack_pop(struct stack *stack)
+{
+	if (stack_empty(stack))
+		return NULL;
+	return &stack->stack[stack->sp--];
+}
+
+struct number *
+stack_popnumber(struct stack *stack)
+{
+	if (stack_empty(stack))
+		return NULL;
+	if (stack->stack[stack->sp].array != NULL) {
+		array_free(stack->stack[stack->sp].array);
+		stack->stack[stack->sp].array = NULL;
+	}
+	if (stack->stack[stack->sp].type != BCODE_NUMBER) {
+		warnx("not a number"); /* XXX remove */
+		return NULL;
+	}
+	return stack->stack[stack->sp--].u.num;
+}
+
+char *
+stack_popstring(struct stack *stack)
+{
+	if (stack_empty(stack))
+		return NULL;
+	if (stack->stack[stack->sp].array != NULL) {
+		array_free(stack->stack[stack->sp].array);
+		stack->stack[stack->sp].array = NULL;
+	}
+	if (stack->stack[stack->sp].type != BCODE_STRING) {
+		warnx("not a string"); /* XXX remove */
+		return NULL;
+	}
+	return stack->stack[stack->sp--].u.string;
+}
+
+void
+stack_clear(struct stack *stack)
+{
+	while (stack->sp >= 0) {
+		stack_free_value(&stack->stack[stack->sp--]);
+	}
+	free(stack->stack);
+	stack_init(stack);
+}
+
+void
+stack_print(FILE *f, const struct stack *stack, const char *prefix, u_int base)
+{
+	ssize_t i;
+
+	for (i = stack->sp; i >= 0; i--) {
+		print_value(f, &stack->stack[i], prefix, base);
+		(void)putc('\n', f);
+	}
+}
+
+
+static struct array *
+array_new(void)
+{
+	struct array *a;
+
+	a = bmalloc(sizeof(*a));
+	a->data = NULL;
+	a->size = 0;
+	return a;
+}
+
+static __inline void
+array_free(struct array *a)
+{
+	size_t i;
+
+	if (a == NULL)
+		return;
+	for (i = 0; i < a->size; i++)
+		stack_free_value(&a->data[i]);
+	free(a->data);
+	free(a);
+}
+
+static struct array *
+array_dup(const struct array *a)
+{
+	struct array	*n;
+	size_t		i;
+
+	if (a == NULL)
+		return NULL;
+	n = array_new();
+	array_grow(n, a->size);
+	for (i = 0; i < a->size; i++)
+		(void)stack_dup_value(&a->data[i], &n->data[i]);
+	return n;
+}
+
+static __inline void
+array_grow(struct array *array, size_t newsize)
+{
+	size_t i;
+
+	array->data = brealloc(array->data, newsize * sizeof(*array->data));
+	for (i = array->size; i < newsize; i++)
+		array->data[i].array = NULL;
+	array->size = newsize;
+}
+
+static __inline void
+array_assign(struct array *array, size_t index, const struct value *v)
+{
+	if (index >= array->size)
+		array_grow(array, index+1);
+	array->data[index] = *v;
+}
+
+static __inline struct value *
+array_retrieve(const struct array *array, size_t index)
+{
+	if (index >= array->size)
+		return NULL;
+	return &array->data[index];
+}
+
+void
+frame_assign(struct stack *stack, size_t index, const struct value *v)
+{
+	struct array *a;
+	struct value n;
+
+	if (stack->sp == -1) {
+		n.type = BCODE_NONE;
+		n.array = NULL;
+		stack_push(stack, &n);
+	}
+
+	a = stack->stack[stack->sp].array;
+	if (a == NULL)
+		a = stack->stack[stack->sp].array = array_new();
+	array_assign(a, index, v);
+}
+
+struct value *
+frame_retrieve(const struct stack *stack, size_t index)
+{
+	struct array *a;
+
+	if (stack->sp == -1)
+		return NULL;
+	a = stack->stack[stack->sp].array;
+	if (a == NULL)
+		a = stack->stack[stack->sp].array = array_new();
+	return array_retrieve(a, index);
+}
--- /dev/null
+++ usr.bin/dc/Makefile
@@ -0,0 +1,10 @@
+#	$OpenBSD: Makefile,v 1.2 2006/11/26 11:31:09 deraadt Exp $
+#	$MidnightBSD: src/usr.bin/dc/Makefile,v 1.1 2007/08/25 18:43:21 archite Exp $
+
+PROG=	dc
+SRCS=	dc.c bcode.c inout.c mem.c stack.c
+COPTS+= -Wall
+LDADD=	-lcrypto
+DPADD=	${LIBCRYPTO}
+
+.include <bsd.prog.mk>
--- /dev/null
+++ usr.bin/dc/bcode.h
@@ -0,0 +1,99 @@
+/*	$OpenBSD: bcode.h,v 1.5 2006/01/16 08:09:25 otto Exp $	*/
+/*	$MidnightBSD: src/usr.bin/dc/bcode.h,v 1.1 2007/08/25 18:43:21 archite Exp $ */
+
+/*
+ * Copyright (c) 2003, Otto Moerbeek <otto at drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <openssl/bn.h>
+
+
+struct number {
+	BIGNUM	*number;
+	u_int	scale;
+};
+
+enum stacktype {
+	BCODE_NONE,
+	BCODE_NUMBER,
+	BCODE_STRING
+};
+
+enum bcode_compare {
+	BCODE_EQUAL,
+	BCODE_NOT_EQUAL,
+	BCODE_LESS,
+	BCODE_NOT_LESS,
+	BCODE_GREATER,
+	BCODE_NOT_GREATER
+};
+
+struct array;
+
+struct value {
+	union {
+		struct number	*num;
+		char		*string;
+	} u;
+	struct array	*array;
+	enum stacktype	type;
+};
+
+struct array {
+	struct value	*data;
+	size_t		size;
+};
+
+struct stack {
+	struct value	*stack;
+	ssize_t		sp;
+	size_t		size;
+};
+
+struct source;
+
+struct vtable {
+	int	(*readchar)(struct source *);
+	void	(*unreadchar)(struct source *);
+	char	*(*readline)(struct source *);
+	void	(*free)(struct source *);
+};
+
+struct source {
+	struct vtable	*vtable;
+	union {
+			FILE *stream;
+			struct {
+				u_char *buf;
+				size_t pos;
+			} string;
+	} u;
+	int		lastchar;
+};
+
+void			init_bmachine(bool);
+void			reset_bmachine(struct source *);
+void			scale_number(BIGNUM *, int);
+void			normalize(struct number *, u_int);
+void			eval(void);
+void			pn(const char *, const struct number *);
+void			pbn(const char *, const BIGNUM *);
+void			negate(struct number *);
+void			split_number(const struct number *, BIGNUM *, BIGNUM *);
+void			bmul_number(struct number *, struct number *,
+			    struct number *);
+
+extern BIGNUM		zero;
--- /dev/null
+++ usr.bin/bc/USD.doc/bc
@@ -0,0 +1,1241 @@
+.\"	$OpenBSD: bc,v 1.9 2004/07/09 10:23:05 jmc Exp $
+.\"	$MidnightBSD: src/usr.bin/bc/USD.doc/bc,v 1.1 2007/08/25 18:43:21 archite Exp $
+.\"
+.\" Copyright (C) Caldera International Inc.  2001-2002.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code and documentation must retain the above
+.\"    copyright notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed or owned by Caldera
+.\"	International, Inc.
+.\" 4. Neither the name of Caldera International, Inc. nor the names of other
+.\"    contributors may be used to endorse or promote products derived from
+.\"    this software without specific prior written permission.
+.\"
+.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"	@(#)bc	6.2 (Berkeley) 4/17/91
+.\"
+.if n \{\
+.po 5n
+.ll 70n
+.\}
+.EH 'USD:6-%''BC \- An Arbitrary Precision Desk-Calculator Language'
+.OH 'BC \- An Arbitrary Precision Desk-Calculator Language''USD:6-%'
+.\".RP
+.TL
+BC \- An Arbitrary Precision Desk-Calculator Language
+.AU
+Lorinda Cherry
+.AU
+Robert Morris
+.AI
+.\" .MH
+.AB
+BC is a language and a compiler for doing arbitrary precision arithmetic
+on the PDP-11 under the
+.UX
+time-sharing
+system.  The output of the compiler is interpreted and executed by
+a collection of routines which can input, output, and do
+arithmetic on indefinitely large integers and on scaled fixed-point
+numbers.
+.PP
+These routines are themselves based on a dynamic storage allocator.
+Overflow does not occur until all available core storage
+is exhausted.
+.PP
+The language has a complete control structure as well as immediate-mode
+operation.  Functions can be defined and saved for later execution.
+.PP
+Two five hundred-digit numbers can be multiplied to give a
+thousand digit result in about ten seconds.
+.PP
+A small collection of library functions is also available,
+including sin, cos, arctan, log, exponential, and Bessel functions of
+integer order.
+.PP
+Some of the uses of this compiler are
+.IP \-
+to do computation with large integers,
+.IP \-
+to do computation accurate to many decimal places,
+.IP \-
+conversion of numbers from one base to another base.
+.AE
+.PP
+.SH
+Introduction
+.PP
+BC is a language and a compiler for doing arbitrary precision
+arithmetic on the
+.UX
+time-sharing system [1].
+The compiler was written to make conveniently available a
+collection of routines (called DC [5]) which are capable of doing
+arithmetic on integers of arbitrary size.  The compiler
+is by no means intended to provide a complete programming
+language.
+It is a minimal language facility.
+.PP
+There is a scaling provision that permits the
+use of decimal point notation.
+Provision is made for input and output in bases other than
+decimal.  Numbers can be converted from decimal to octal by
+simply setting the output base to equal 8.
+.PP
+The actual limit on the number of digits that can
+be handled depends on the amount of storage available on the machine.
+Manipulation of numbers with many hundreds of digits
+is possible even on the smallest versions of
+.UX .
+.PP
+The syntax of BC has been deliberately selected to agree
+substantially with the C language [2].  Those who
+are familiar with C will find few surprises in this language.
+.SH
+Simple Computations with Integers
+.PP
+The simplest kind of statement is an arithmetic expression
+on a line by itself.
+For instance, if you type in the line:
+.DS
+.ft B
+142857 + 285714
+.ft P
+.DE
+the program responds immediately with the line
+.DS
+.ft B
+428571
+.ft P
+.DE
+The operators \-, *, /, %, and ^ can also be used; they
+indicate subtraction, multiplication, division, remaindering, and
+exponentiation, respectively.  Division of integers produces an
+integer result truncated toward zero.
+Division by zero produces an error
+comment.
+.PP
+Any term in an expression may be prefixed by a minus sign to
+indicate that it is to be negated (the `unary' minus sign).
+The expression
+.DS
+.ft B
+7+\-3
+.ft P
+.DE
+is interpreted to mean that \-3 is to be added to 7.
+.PP
+More complex expressions with several operators and with
+parentheses are interpreted just as in
+Fortran, with ^ having the greatest binding
+power, then * and % and /, and finally + and \-.
+Contents of parentheses are evaluated before material
+outside the parentheses.
+Exponentiations are
+performed from right to left and the other operators
+from left to right.
+The two expressions
+.DS
+.ft B
+a^b^c  and  a^(b^c)
+.ft P
+.DE
+are equivalent, as are the two expressions
+.DS
+.ft B
+a*b*c  and  (a*b)*c
+.ft P
+.DE
+BC shares with Fortran and C the undesirable convention that
+.DS
+\fBa/b*c\fP  is equivalent to  \fB(a/b)*c\fP
+.ft P
+.DE
+.PP
+Internal storage registers to hold numbers have single lower-case
+letter names.  The value of an expression can be assigned to
+a register in the usual way.  The statement
+.DS
+.ft B
+x = x + 3
+.ft P
+.DE
+has the effect of increasing by three the value of the contents of the
+register named x.
+When, as in this case, the outermost operator is an =, the
+assignment is performed but the result is not printed.
+Only 26 of these named storage registers are available.
+.PP
+There is a built-in square root function whose
+result is truncated to an integer (but see scaling below).
+The lines
+.DS
+.ft B
+x = sqrt(191)
+x
+.ft P
+.DE
+produce the printed result
+.DS
+.ft B
+13
+.ft P
+.DE
+.SH
+Bases
+.PP
+There are special internal quantities, called `ibase' and `obase'.
+The contents of `ibase', initially set to 10,
+determines the base used for interpreting numbers read in.
+For example, the lines
+.DS
+.ft B
+ibase = 8
+11
+.ft P
+.DE
+will produce the output line
+.DS
+.ft B
+9
+.ft P
+.DE
+and you are all set up to do octal to decimal conversions.
+Beware, however of trying to change the input base back
+to decimal by typing
+.DS
+.ft B
+ibase = 10
+.ft P
+.DE
+Because the number 10 is interpreted as octal, this statement will
+have no effect.
+For those who deal in hexadecimal notation,
+the characters A\-F are permitted in numbers
+(no matter what base is in effect)
+and are
+interpreted as digits having values 10\-15 respectively.
+The statement
+.DS
+.ft B
+ibase = A
+.ft P
+.DE
+will change you back to decimal input base no matter what the
+current input base is.
+Negative and large positive input bases are
+permitted but useless.
+No mechanism has been provided for the input of arbitrary
+numbers in bases less than 1 and greater than 16.
+.PP
+The contents of `obase', initially set to 10, are used as the base for output
+numbers.  The lines
+.DS
+.ft B
+obase = 16
+1000
+.ft P
+.DE
+will produce the output line
+.DS
+.ft B
+3E8
+.ft P
+.DE
+which is to be interpreted as a 3-digit hexadecimal number.
+Very large output bases are permitted, and they are sometimes useful.
+For example, large numbers can be output in groups of five digits
+by setting `obase' to 100000.
+Strange (i.e. 1, 0, or negative) output bases are
+handled appropriately.
+.PP
+Very large numbers are split across lines with 70 characters per line.
+Lines which are continued end with \\.
+Decimal output conversion is practically instantaneous, but output
+of very large numbers (i.e., more than 100 digits) with other bases
+is rather slow.
+Non-decimal output conversion of
+a one hundred digit number takes about
+three seconds.
+.PP
+It is best to remember that `ibase' and `obase' have no effect
+whatever on the course of internal computation or
+on the evaluation of expressions, but only affect input and
+output conversion, respectively.
+.SH
+Scaling
+.PP
+A third special internal quantity called `scale' is
+used to determine the scale of calculated
+quantities.
+Numbers may have
+up to a specific number of decimal digits after the decimal point.
+This fractional part is retained in further computations.
+We refer to the number of digits after the decimal point of
+a number as its scale.
+The current implementation allows scales to be as large as can be
+represented by a 32-bit unsigned number minus one.
+This is a non-portable extension.
+The original implementation allowed for a maximum scale of 99.
+.PP
+When two scaled numbers are combined by
+means of one of the arithmetic operations, the result
+has a scale determined by the following rules.  For
+addition and subtraction, the scale of the result is the larger
+of the scales of the two operands.  In this case,
+there is never any truncation of the result.
+For multiplications, the scale of the result is never
+less than the maximum of the two scales of the operands,
+never more than the sum of the scales of the operands
+and, subject to those two restrictions,
+the scale of the result is set equal to the contents of the internal
+quantity `scale'.
+The scale of a quotient is the contents of the internal
+quantity `scale'.  The scale of a remainder is
+the sum of the scales of the quotient and the divisor.
+The result of an exponentiation is scaled as if
+the implied multiplications were performed.
+An exponent must be an integer.
+The scale of a square root is set to the maximum of the scale
+of the argument and the contents of `scale'.
+.PP
+All of the internal operations are actually carried out in terms
+of integers, with digits being discarded when necessary.
+In every case where digits are discarded, truncation and
+not rounding is performed.
+.PP
+The contents of
+`scale' must be no greater than
+4294967294 and no less than 0.  It is initially set to 0.
+.PP
+The internal quantities `scale', `ibase', and `obase' can be
+used in expressions just like other variables.
+The line
+.DS
+.ft B
+scale = scale + 1
+.ft P
+.DE
+increases the value of `scale' by one, and the line
+.DS
+.ft B
+scale
+.ft P
+.DE
+causes the current value of `scale' to be printed.
+.PP
+The value of `scale' retains its meaning as a
+number of decimal digits to be retained in internal
+computation even when `ibase' or `obase' are not equal to 10.
+The internal computations (which are still conducted in decimal,
+regardless of the bases) are performed to the specified number
+of decimal digits, never hexadecimal or octal or any
+other kind of digits.
+.SH
+Functions
+.PP
+The name of a function is a single lower-case letter.
+Function names are permitted to collide with simple
+variable names.
+Twenty-six different defined functions are permitted
+in addition to the twenty-six variable names.
+The line
+.DS
+.ft B
+	define a(x){
+.ft P
+.DE
+begins the definition of a function with one argument.
+This line must be followed by one or more statements,
+which make up the body of the function, ending
+with a right brace }.
+Return of control from a function occurs when a return
+statement is executed or when the end of the function is reached.
+The return statement can take either
+of the two forms
+.DS
+.ft B
+return
+return(x)
+.ft P
+.DE
+In the first case, the value of the function is 0, and in
+the second, the value of the expression in parentheses.
+.PP
+Variables used in the function can be declared as automatic
+by a statement of the form
+.DS
+.ft B
+auto x,y,z
+.ft P
+.DE
+There can be only one `auto' statement in a function and it must
+be the first statement in the definition.
+These automatic variables are allocated space and initialized
+to zero on entry to the function and thrown away on return.  The
+values of any variables with the same names outside the function
+are not disturbed.
+Functions may be called recursively and the automatic variables
+at each level of call are protected.
+The parameters named in a function definition are treated in
+the same way as the automatic variables of that function
+with the single exception that they are given a value
+on entry to the function.
+An example of a function definition is
+.DS
+.ft B
+	define a(x,y){
+		auto z
+		z = x*y
+		return(z)
+	}
+.ft P
+.DE
+The value of this function, when called, will be the
+product of its
+two arguments.
+.PP
+A function is called by the appearance of its name
+followed by a string of arguments enclosed in
+parentheses and separated by commas.
+The result
+is unpredictable if the wrong number of arguments is used.
+.PP
+Functions with no arguments are defined and called using
+parentheses with nothing between them: b().
+.PP
+If the function
+.ft I
+a
+.ft
+above has been defined, then the line
+.DS
+.ft B
+a(7,3.14)
+.ft P
+.DE
+would cause the result 21.98 to be printed and the line
+.DS
+.ft B
+x = a(a(3,4),5)
+.ft P
+.DE
+would cause the value of x to become 60.
+.SH
+Subscripted Variables
+.PP
+A single lower-case letter variable name
+followed by an expression in brackets is called a subscripted
+variable (an array element).
+The variable name is called the array name and the expression
+in brackets is called the subscript.
+Only one-dimensional arrays are
+permitted.  The names of arrays are permitted to
+collide with the names of simple variables and function names.
+Any fractional
+part of a subscript is discarded before use.
+Subscripts must be greater than or equal to zero and 
+less than or equal to 2047.
+.PP
+Subscripted variables may be freely used in expressions, in
+function calls, and in return statements.
+.PP
+An array name may be used as an argument to a function,
+or may be declared as automatic in
+a function definition by the use of empty brackets:
+.DS
+.ft B
+f(a[\|])
+define f(a[\|])
+auto a[\|]
+.ft P
+.DE
+When an array name is so used, the whole contents of the array
+are copied for the use of the function, and thrown away on exit
+from the function.
+Array names which refer to whole arrays cannot be used
+in any other contexts.
+.SH
+Control Statements
+.PP
+The `if', the `while', and the `for' statements
+may be used to alter the flow within programs or to cause iteration.
+The range of each of them is a statement or
+a compound statement consisting of a collection of
+statements enclosed in braces.
+They are written in the following way
+.DS
+.ft B
+if(relation) statement
+if(relation) statement else statement
+while(relation) statement
+for(expression1; relation; expression2) statement
+.ft P
+.DE
+or
+.DS
+.ft B
+if(relation) {statements}
+if(relation) {statements} else {statements}
+while(relation) {statements}
+for(expression1; relation; expression2) {statements}
+.ft P
+.DE
+.PP
+A relation in one of the control statements is an expression of the form
+.DS
+.ft B
+x>y
+.ft P
+.DE
+where  two expressions are related by one of the six relational
+operators `<', `>', `<=', `>=', `==', or `!='.
+The relation `=='
+stands for `equal to' and `!=' stands for `not equal to'.
+The meaning of the remaining relational operators is
+clear.
+.PP
+BEWARE of using `=' instead of `==' in a relational.  Unfortunately,
+both of them are legal, so you will not get a diagnostic
+message, but `=' really will not do a comparison.
+.PP
+The `if' statement causes execution of its range
+if and only if the relation is true.
+Then control passes to the next statement in sequence.
+If an `else' branch is present, the statements in this branch are
+executed if the relation is false.
+The `else' keyword is a non-portable extension.
+.PP
+The `while' statement causes execution of its range
+repeatedly as long as the relation
+is true.  The relation is tested before each execution
+of its range and if the relation
+is false, control passes to the next statement beyond the range
+of the while.
+.PP
+The `for' statement begins
+by executing `expression1'.  Then the relation is tested
+and, if true, the statements in the range of the `for' are executed.
+Then `expression2' is executed.  The relation is tested, and so on.
+The typical use of the `for' statement is for a controlled iteration,
+as in the statement
+.DS
+.ft B
+for(i=1; i<=10; i=i+1) i
+.ft P
+.DE
+which will print the integers from 1 to 10.
+Here are some examples of the use of the control statements.
+.DS
+.ft B
+define f(n){
+auto i, x
+x=1
+for(i=1; i<=n; i=i+1) x=x*i
+return(x)
+}
+.ft P
+.DE
+The line
+.DS
+.ft B
+	f(a)
+.ft P
+.DE
+will print
+.ft I
+a
+.ft
+factorial if
+.ft I
+a
+.ft
+is a positive integer.
+Here is the definition of a function which will
+compute values of the binomial coefficient
+(m and n are assumed to be positive integers).
+.DS
+.ft B
+define b(n,m){
+auto x, j
+x=1
+for(j=1; j<=m; j=j+1) x=x*(n\-j+1)/j
+return(x)
+}
+.ft P
+.DE
+The following function computes values of the exponential function
+by summing the appropriate series
+without regard for possible truncation errors:
+.DS
+.ft B
+scale = 20
+define e(x){
+	auto a, b, c, d, n
+	a = 1
+	b = 1
+	c = 1
+	d = 0
+	n = 1
+	while(1==1){
+		a = a*x
+		b = b*n
+		c = c + a/b
+		n = n + 1
+		if(c==d) return(c)
+		d = c
+	}
+}
+.ft P
+.DE
+.SH
+Some Details
+.PP
+There are some language features that every user should know
+about even if he will not use them.
+.PP
+Normally statements are typed one to a line.  It is also permissible
+to type several statements on a line separated by semicolons.
+.PP
+If an assignment statement is parenthesized, it then has
+a value and it can be used anywhere that an expression can.
+For example, the line
+.DS
+.ft B
+(x=y+17)
+.ft P
+.DE
+not only makes the indicated assignment, but also prints the
+resulting value.
+.PP
+Here is an example of a use of the value of an
+assignment statement even when it is not parenthesized.
+.DS
+.ft B
+x = a[i=i+1]
+.ft P
+.DE
+causes a value to be assigned to x and also increments i
+before it is used as a subscript.
+.PP
+The following constructs work in BC in exactly the same manner
+as they do in the C language.  Consult the appendix or the
+C manuals [2] for their exact workings.
+.DS
+.ft B
+.ta 2i
+x=y=z  is the same as	x=(y=z)
+x += y	x = x+y
+x \-= y	x = x\-y
+x *= y	x = x*y
+x /= y	x = x/y
+x %= y	x = x%y
+x ^= y	x = x^y
+x++	(x=x+1)\-1
+x\-\-	(x=x\-1)+1
+++x	x = x+1
+\-\-x	x = x\-1
+.ft P
+.DE
+Even if you don't intend to use the constructs,
+if you type one inadvertently, something correct but unexpected
+may happen.
+.SH
+Three Important Things
+.PP
+1.  To exit a BC program, type `quit'.
+.PP
+2. There is a comment convention identical to that of C and
+of PL/I.  Comments begin with `/*' and end with `*/'.
+As a non-portable extension, comments may also start with a `#' and end with
+a newline.
+The newline is not part of the comment.
+.PP
+3. There is a library of math functions which may be obtained by
+typing at command level
+.DS
+.ft B
+bc \-l
+.ft P
+.DE
+This command will load a set of library functions
+which, at the time of writing, consists of sine (named `s'),
+cosine (`c'), arctangent (`a'), natural logarithm (`l'),
+exponential (`e') and Bessel functions of integer order (`j(n,x)').  Doubtless more functions will be added
+in time.
+The library sets the scale to 20.  You can reset it to something
+else if you like.
+The design of these mathematical library routines
+is discussed elsewhere [3].
+.PP
+If you type
+.DS
+.ft B
+bc file ...
+.ft P
+.DE
+BC will read and execute the named file or files before accepting
+commands from the keyboard.  In this way, you may load your
+favorite programs and function definitions.
+.SH
+Acknowledgement
+.PP
+The compiler is written in YACC [4]; its original
+version  was written by S. C. Johnson.
+.SH
+References
+.IP [1]
+K. Thompson and D. M. Ritchie,
+.ft I
+UNIX Programmer's Manual,
+.ft
+Bell Laboratories,
+1978.
+.IP [2]
+B. W. Kernighan and
+D. M. Ritchie,
+.ft I
+The C Programming Language,
+.ft
+Prentice-Hall, 1978.
+.IP [3]
+R. Morris,
+.ft I
+A Library of Reference Standard Mathematical Subroutines,
+.ft
+Bell Laboratories internal memorandum, 1975.
+.IP [4]
+S. C. Johnson,
+.ft I
+YACC \(em Yet Another Compiler-Compiler.
+.ft
+Bell Laboratories Computing Science Technical Report #32, 1978.
+.IP [5]
+R. Morris and L. L. Cherry,
+.ft I
+DC \- An Interactive Desk Calculator.
+.ft
+.LP
+.bp
+.ft B
+.DS C
+Appendix
+.DE
+.ft
+.NH
+Notation
+.PP
+In the following pages syntactic categories are in \fIitalics\fP;
+literals are in \fBbold\fP; material in brackets [\|] is optional.
+.NH
+Tokens
+.PP
+Tokens consist of keywords, identifiers, constants, operators,
+and separators.
+Token separators may be blanks, tabs or comments.
+Newline characters or semicolons separate statements.
+.NH 2
+Comments
+.PP
+Comments are introduced by the characters /* and terminated by
+*/.
+As a non-portable extension, comments may also start with a # and
+end with a newline.
+The newline is not part of the comment.
+.NH 2
+Identifiers
+.PP
+There are three kinds of identifiers \- ordinary identifiers, array identifiers
+and function identifiers.
+All three types consist of single lower-case letters.
+Array identifiers are followed by square brackets, possibly
+enclosing an expression describing a subscript.
+Arrays are singly dimensioned and may contain up to 2048
+elements.
+Indexing begins at zero so an array may be indexed from 0 to 2047.
+Subscripts are truncated to integers.
+Function identifiers are followed by parentheses, possibly enclosing arguments.
+The three types of identifiers do not conflict;
+a program can have a variable named \fBx\fP,
+an array named \fBx\fP and a function named \fBx\fP, all of which are separate and
+distinct.
+.NH 2
+Keywords
+.PP
+The following are reserved keywords:
+.ft B
+.ta .5i 1.0i
+.nf
+	ibase	if
+	obase	break
+	scale	define
+	sqrt	auto
+	length	return
+	while	quit
+	for	continue
+	else	last
+	print
+.fi
+.ft
+.NH 2
+Constants
+.PP
+Constants consist of arbitrarily long numbers
+with an optional decimal point.
+The hexadecimal digits \fBA\fP\-\fBF\fP are also recognized as digits with
+values 10\-15, respectively.
+.NH 1
+Expressions
+.PP
+The value of an expression is printed unless the main
+operator is an assignment.
+The value printed is assigned to the special variable \fBlast\fP.
+A single dot may be used as a synonym for \fBlast\fP.
+This is a non-portable extension.
+Precedence is the same as the order
+of presentation here, with highest appearing first.
+Left or right associativity, where applicable, is
+discussed with each operator.
+.bp
+.NH 2
+Primitive expressions
+.NH 3
+Named expressions
+.PP
+Named expressions are
+places where values are stored.
+Simply stated,
+named expressions are legal on the left
+side of an assignment.
+The value of a named expression is the value stored in the place named.
+.NH 4
+\fIidentifiers\fR
+.PP
+Simple identifiers are named expressions.
+They have an initial value of zero.
+.NH 4
+\fIarray-name\fP\|[\|\fIexpression\fP\|]
+.PP
+Array elements are named expressions.
+They have an initial value of zero.
+.NH 4
+\fBscale\fR, \fBibase\fR and \fBobase\fR
+.PP
+The internal registers
+\fBscale\fP, \fBibase\fP and \fBobase\fP are all named expressions.
+\fBscale\fP is the number of digits after the decimal point to be
+retained in arithmetic operations.
+\fBscale\fR has an initial value of zero.
+\fBibase\fP and \fBobase\fP are the input and output number
+radix respectively.
+Both \fBibase\fR and \fBobase\fR have initial values of 10.
+.NH 3
+Function calls
+.NH 4
+\fIfunction-name\fB\|(\fR[\fIexpression\fR\|[\fB,\|\fIexpression\|\fR.\|.\|.\|]\|]\fB)
+.PP
+A function call consists of a function name followed by parentheses
+containing a comma-separated list of
+expressions, which are the function arguments.
+A whole array passed as an argument is specified by the
+array name followed by empty square brackets.
+All function arguments are passed by
+value.
+As a result, changes made to the formal parameters have
+no effect on the actual arguments.
+If the function terminates by executing a return
+statement, the value of the function is
+the value of the expression in the parentheses of the return
+statement or is zero if no expression is provided
+or if there is no return statement.
+.NH 4
+sqrt\|(\|\fIexpression\fP\|)
+.PP
+The result is the square root of the expression.
+The result is truncated in the least significant decimal place.
+The scale of the result is
+the scale of the expression or the
+value of
+.ft B
+scale,
+.ft
+whichever is larger.
+.NH 4
+length\|(\|\fIexpression\fP\|)
+.PP
+The result is the total number of significant decimal digits in the expression.
+The scale of the result is zero.
+.NH 4
+scale\|(\|\fIexpression\fP\|)
+.PP
+The result is the scale of the expression.
+The scale of the result is zero.
+.NH 3
+Constants
+.PP
+Constants are primitive expressions.
+.NH 3
+Parentheses
+.PP
+An expression surrounded by parentheses is
+a primitive expression.
+The parentheses are used to alter the
+normal precedence.
+.NH 2
+Unary operators
+.PP
+The unary operators
+bind right to left.
+.NH 3
+\-\|\fIexpression\fP
+.PP
+The result is the negative of the expression.
+.NH 3
+++\|\fInamed-expression\fP
+.PP
+The named expression is
+incremented by one.
+The result is the value of the named expression after
+incrementing.
+.NH 3
+\-\-\|\fInamed-expression\fP
+.PP
+The named expression is
+decremented by one.
+The result is the value of the named expression after
+decrementing.
+.NH 3
+\fInamed-expression\fP\|++
+.PP
+The named expression is
+incremented by one.
+The result is the value of the named expression before
+incrementing.
+.NH 3
+\fInamed-expression\fP\|\-\-
+.PP
+The named expression is
+decremented by one.
+The result is the value of the named expression before
+decrementing.
+.NH 2
+Exponentiation operator
+.PP
+The exponentiation operator binds right to left.
+.NH 3
+\fIexpression\fP ^ \fIexpression\fP
+.PP
+The result is the first
+expression raised to the power of the
+second expression.
+The second expression must be an integer.
+If \fIa\fP
+is the scale of the left expression
+and \fIb\fP is the absolute value
+of the right expression,
+then the scale of the result is:
+.PP
+min\|(\|\fIa\(mub\fP,\|max\|(\|\fBscale\fP,\|\fIa\fP\|)\|)
+.NH 2
+Multiplicative operators
+.PP
+The operators *, /, % bind left to right.
+.NH 3
+\fIexpression\fP * \fIexpression\fP
+.PP
+The result is the product
+of the two expressions.
+If \fIa\fP and \fIb\fP are the
+scales of the two expressions,
+then the scale of the result is:
+.PP
+min\|(\|\fIa+b\fP,\|max\|(\|\fBscale\fP,\|\fIa\fP,\|\fIb\fP\|)\|)
+.NH 3
+\fIexpression\fP / \fIexpression\fP
+.PP
+The result is the quotient of the two expressions.
+The scale of the result is the value of \fBscale\fR.
+.NH 3
+\fIexpression\fP % \fIexpression\fP
+.PP
+The % operator produces the remainder of the division
+of the two expressions.
+More precisely,
+\fIa\fP%\fIb\fP is \fIa\fP\-\fIa\fP/\fIb\fP*\fIb\fP.
+.PP
+The scale of the result is the sum of the scale of
+the divisor and the value of
+.ft B
+scale
+.ft
+.NH 2
+Additive operators
+.PP
+The additive operators bind left to right.
+.NH 3
+\fIexpression\fP + \fIexpression\fP
+.PP
+The result is the sum of the two expressions.
+The scale of the result is
+the maximum of the scales of the expressions.
+.NH 3
+\fIexpression\fP \- \fIexpression\fP
+.PP
+The result is the difference of the two expressions.
+The scale of the result is the
+maximum of the scales of the expressions.
+.NH 2
+assignment operators
+.PP
+The assignment operators bind right to left.
+.NH 3
+\fInamed-expression\fP = \fIexpression\fP
+.PP
+This expression results in assigning the value of the expression
+on the right
+to the named expression on the left.
+.NH 3
+\fInamed-expression\fP += \fIexpression\fP
+.NH 3
+\fInamed-expression\fP \-= \fIexpression\fP
+.NH 3
+\fInamed-expression\fP *= \fIexpression\fP
+.NH 3
+\fInamed-expression\fP /= \fIexpression\fP
+.NH 3
+\fInamed-expression\fP %= \fIexpression\fP
+.NH 3
+\fInamed-expression\fP ^= \fIexpression\fP
+.PP
+The result of the above expressions is equivalent
+to ``named expression = named expression OP expression'',
+where OP is the operator after the = sign.
+.NH 1
+Relations
+.PP
+Unlike all other operators, the relational operators
+are only valid as the object of an \fBif\fP, \fBwhile\fP,
+or inside a \fBfor\fP statement.
+.NH 2
+\fIexpression\fP < \fIexpression\fP
+.NH 2
+\fIexpression\fP > \fIexpression\fP
+.NH 2
+\fIexpression\fP <= \fIexpression\fP
+.NH 2
+\fIexpression\fP >= \fIexpression\fP
+.NH 2
+\fIexpression\fP == \fIexpression\fP
+.NH 2
+\fIexpression\fP != \fIexpression\fP
+.NH 1
+Storage classes
+.PP
+There are only two storage classes in BC, global and automatic
+(local).
+Only identifiers that are to be local to a function need be 
+declared with the \fBauto\fP command.
+The arguments to a function
+are local to the function.
+All other identifiers are assumed to be global
+and available to all functions.
+All identifiers, global and local, have initial values
+of zero.
+Identifiers declared as \fBauto\fP are allocated on entry to the function 
+and released on returning from the function.
+They therefore do not retain values between function calls.
+\fBauto\fP arrays are specified by the array name followed by empty square brackets.
+.PP
+Automatic variables in BC do not work in exactly the same way
+as in either C or PL/I.  On entry to a function, the old values of
+the names that appear as parameters and as automatic
+variables are pushed onto a stack.  
+Until return is made from the function, reference to these
+names refers only to the new values.
+.NH 1
+Statements
+.PP
+Statements must be separated by semicolon or newline.
+Except where altered by control statements, execution
+is sequential.
+.NH 2
+Expression statements
+.PP
+When a statement is an expression, unless
+the main operator is an assignment, the value
+of the expression is printed, followed by a newline character.
+.NH 2
+Compound statements
+.PP
+Statements may be grouped together and used when one statement is expected
+by surrounding them with { }.
+.NH 2
+Quoted string statements
+.PP
+"any string"
+.sp .5
+This statement prints the string inside the quotes.
+.NH 2
+If statements
+.sp .5
+\fBif\|(\|\fIrelation\fB\|)\|\fIstatement\fR
+.PP
+The substatement is executed if the relation is true.
+.NH 2
+If-else statements
+.sp .5
+\fBif\|(\|\fIrelation\fB\|)\|\fIstatement\fB\|else\|\fIstatement\fR
+.PP
+The first substatement is executed if the relation is true, the second
+substatement if the relation is false.
+The \fBif-else\fR statement is a non-portable extension.
+.NH 2
+While statements
+.sp .5
+\fBwhile\|(\|\fIrelation\fB\|)\|\fIstatement\fR
+.PP
+The statement is executed while the relation
+is true.
+The test occurs before each execution of the statement.
+.NH 2
+For statements
+.sp .5
+\fBfor\|(\|\fIexpression\fB; \fIrelation\fB; \fIexpression\fB\|)\|\fIstatement\fR
+.PP
+The \fBfor\fR statement is the same as
+.nf
+.ft I
+	first-expression
+	\fBwhile\|(\fPrelation\|\fB) {\fP
+		statement
+		last-expression
+	}
+.ft R
+.fi
+.PP
+All three expressions may be left out.
+This is a non-portable extension.
+.NH 2
+Break statements
+.sp .5
+\fBbreak\fP
+.PP
+\fBbreak\fP causes termination of a \fBfor\fP or \fBwhile\fP statement.
+.NH 2
+Continue statements
+.sp .5
+\fBcontinue\fP
+.PP
+\fBcontinue\fP causes the next iteration of a \fBfor\fP or \fBwhile\fP
+statement to start, skipping the remainder of the loop.
+For a \fBwhile\fP statement, execution continues with the evaluation
+of the condition.
+For a \fBfor\fP statement, execution continues with evaluation of
+the last-expression.
+The \fBcontinue\fP statement is a non-portable extension.
+.NH 2
+Auto statements
+.sp .5
+\fBauto \fIidentifier\fR\|[\|\fB,\fIidentifier\fR\|]
+.PP
+The \fBauto\fR statement causes the values of the identifiers to be pushed down.
+The identifiers can be ordinary identifiers or array identifiers.
+Array identifiers are specified by following the array name by empty square
+brackets.
+The auto statement must be the first statement
+in a function definition.
+.NH 2
+Define statements
+.sp .5
+.nf
+\fBdefine(\|\fR[\fIparameter\|\fR[\fB\|,\|\fIparameter\|.\|.\|.\|\fR]\|]\|\fB)\|{\fI
+	statements\|\fB}\fR
+.fi
+.PP
+The \fBdefine\fR statement defines a function.
+The parameters may
+be ordinary identifiers or array names.
+Array names must be followed by empty square brackets.
+As a non-portable extension, the opening brace may also appear on the
+next line.
+.NH 2
+Return statements
+.sp .5
+\fBreturn\fP
+.sp .5
+\fBreturn(\fI\|expression\|\fB)\fR
+.PP
+The \fBreturn\fR statement causes termination of a function,
+popping of its auto variables, and
+specifies the result of the function.
+The first form is equivalent to \fBreturn(0)\fR.
+The result of the function is the result of the expression
+in parentheses.
+Leaving out the expression between parentheses is equivalent to
+\fBreturn(0)\fR.
+As a non-portable extension, the parentheses may be left out.
+.NH 2
+Print
+.PP
+The \fBprint\fR statement takes a list of comma-separated expressions.
+Each expression in the list is evaluated and the computed
+value is printed and assigned to the variable `last'.
+No trailing newline is printed.
+The expression may also be a string enclosed in double quotes.
+Within these strings the following escape sequences may be used:
+\ea 
+for bell (alert),
+`\eb'
+for backspace,
+`\ef'
+for formfeed,
+`\en'
+for newline,   
+`\er'
+for carriage return,
+`\et'
+`for tab,
+`\eq'
+for double quote and
+`\e\e'
+for backslash.
+Any other character following a backslash will be ignored.
+Strings will not be assigned to `last'.
+The \fBprint\fR statement is a non-portable extension.
+.NH 2
+Quit
+.PP
+The \fBquit\fR statement stops execution of a BC program and returns
+control to UNIX when it is first encountered.
+Because it is not treated as an executable statement,
+it cannot be used
+in a function definition or in an 
+.ft B
+if, for,
+.ft
+or
+.ft B
+while
+.ft
+statement.
--- /dev/null
+++ usr.bin/bc/USD.doc/Makefile
@@ -0,0 +1,11 @@
+#	$OpenBSD: Makefile,v 1.3 2004/02/01 15:18:01 jmc Exp $
+#	$MidnightBSD: src/usr.bin/bc/USD.doc/Makefile,v 1.1 2007/08/25 18:43:21 archite Exp $
+
+DIR=	usd/06.bc
+SRCS=	bc
+MACROS=	-ms
+
+paper.txt: ${SRCS}
+	${ROFF} -Tascii ${SRCS} > ${.TARGET}
+
+.include <bsd.doc.mk>
--- /dev/null
+++ usr.bin/dc/USD.doc/dc
@@ -0,0 +1,753 @@
+.\"	$OpenBSD: dc,v 1.2 2003/09/22 19:08:27 otto Exp $
+.\"	$MidnightBSD: src/usr.bin/dc/USD.doc/dc,v 1.1 2007/08/25 18:43:21 archite Exp $
+.\"
+.\" Copyright (C) Caldera International Inc.  2001-2002.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code and documentation must retain the above
+.\"    copyright notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed or owned by Caldera
+.\"	International, Inc.
+.\" 4. Neither the name of Caldera International, Inc. nor the names of other
+.\"    contributors may be used to endorse or promote products derived from
+.\"    this software without specific prior written permission.
+.\"
+.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"	@(#)dc	8.1 (Berkeley) 6/8/93
+.\"
+.EH 'USD:5-%''DC \- An Interactive Desk Calculator'
+.OH 'DC \- An Interactive Desk Calculator''USD:5-%'
+.\".RP
+.\" ....TM 75-1271-8 39199 39199-11
+.ND
+.TL
+DC \- An Interactive Desk Calculator
+.AU "MH 2C-524" 3878
+Robert Morris
+.AU
+Lorinda Cherry
+.AI
+.\" .MH
+.AB
+DC is an interactive desk calculator program implemented
+on the
+.UX
+time-sharing system to do arbitrary-precision
+integer arithmetic.
+It has provision for manipulating scaled fixed-point numbers and
+for input and output in bases other than decimal.
+.PP
+The size of numbers that can be manipulated is limited
+only by available core storage.
+On typical implementations of
+.UX ,
+the size of numbers that
+can be handled varies from several hundred digits on the smallest
+systems to several thousand on the largest.
+.AE
+.PP
+.SH
+.PP
+.ft I
+Editor's note: the description of the implementation details of DC in this
+paper is only valid for the original version of DC.
+The current version of DC uses a different approach.
+.ft
+.PP
+DC is an arbitrary precision arithmetic package implemented
+on the
+.UX
+time-sharing system
+in the form of an interactive desk calculator.
+It works like a stacking calculator using reverse Polish notation.
+Ordinarily DC operates on decimal integers, but one may
+specify an input base, output base, and a number of fractional
+digits to be maintained.
+.PP
+A language called BC [1] has been developed which accepts
+programs written in the familiar style of higher-level
+programming languages and compiles output which is
+interpreted by DC.
+Some of the commands described below were designed
+for the compiler interface and are not easy for a human user
+to manipulate.
+.PP
+Numbers that are typed into DC are put on a push-down
+stack.
+DC commands work by taking the top number or two
+off the stack, performing the desired operation, and pushing the result
+on the stack.
+If an argument is given,
+input is taken from that file until its end,
+then from the standard input.
+.SH
+SYNOPTIC DESCRIPTION
+.PP
+Here we describe the DC commands that are intended
+for use by people.  The additional commands that are
+intended to be invoked by compiled output are
+described in the detailed description.
+.PP
+Any number of commands are permitted on a line.
+Blanks and new-line characters are ignored except within numbers
+and in places where a register name is expected.
+.PP
+The following constructions are recognized:
+.SH
+number
+.IP
+The value of the number is pushed onto the main stack.
+A number is an unbroken string of the digits 0-9
+and the capital letters A\-F which are treated as digits
+with values 10\-15 respectively.
+The number may be preceded by an underscore _ to input a
+negative number.
+Numbers may contain decimal points.
+.SH
++  \-  *  %  ^
+.IP
+The
+top two values on the stack are added
+(\fB+\fP),
+subtracted
+(\fB\-\fP),
+multiplied (\fB*\fP),
+divided (\fB/\fP),
+remaindered (\fB%\fP),
+or exponentiated (^).
+The two entries are popped off the stack;
+the result is pushed on the stack in their place.
+The result of a division is an integer truncated toward zero.
+See the detailed description below for the treatment of
+numbers with decimal points.
+An exponent must not have any digits after the decimal point.
+.SH
+s\fIx\fP
+.IP
+The
+top of the main stack is popped and stored into
+a register named \fIx\fP, where \fIx\fP may be any character.
+If
+the
+.ft B
+s
+.ft
+is capitalized,
+.ft I
+x
+.ft
+is treated as a stack and the value is pushed onto it.
+Any character, even blank or new-line, is a valid register name.
+.SH
+l\fIx\fP
+.IP
+The
+value in register
+.ft I
+x
+.ft
+is pushed onto the stack.
+The register
+.ft I
+x
+.ft
+is not altered.
+If the
+.ft B
+l
+.ft
+is capitalized,
+register
+.ft I
+x
+.ft
+is treated as a stack and its top value is popped onto the main stack.
+.LP
+All registers start with empty value which is treated as a zero
+by the command \fBl\fP and is treated as an error by the command \fBL\fP.
+.SH
+d
+.IP
+The
+top value on the stack is duplicated.
+.SH
+p
+.IP
+The top value on the stack is printed.
+The top value remains unchanged.
+.SH
+f
+.IP
+All values on the stack and in registers are printed.
+.SH
+x
+.IP
+treats the top element of the stack as a character string,
+removes it from the stack, and
+executes it as a string of DC commands.
+.SH
+[ ... ]
+.IP
+puts the bracketed character string onto the top of the stack.
+.SH
+q
+.IP
+exits the program.
+If executing a string, the recursion level is
+popped by two.
+If
+.ft B
+q
+.ft
+is capitalized,
+the top value on the stack is popped and the string execution level is popped
+by that value.
+.SH
+<\fIx\fP  >\fIx\fP  =\fIx\fP  !<\fIx\fP  !>\fIx\fP  !=\fIx\fP
+.IP
+The
+top two elements of the stack are popped and compared.
+Register
+.ft I
+x
+.ft
+is executed if they obey the stated
+relation.
+Exclamation point is negation.
+.SH
+v
+.IP
+replaces the top element on the stack by its square root.
+The square root of an integer is truncated to an integer.
+For the treatment of numbers with decimal points, see
+the detailed description below.
+.SH
+!
+.IP
+interprets the rest of the line as a
+.UX
+command.
+Control returns to DC when the
+.UX
+command terminates.
+.SH
+c
+.IP
+All values on the stack are popped; the stack becomes empty.
+.SH
+i
+.IP
+The top value on the stack is popped and used as the
+number radix for further input.
+If \fBi\fP is capitalized, the value of
+the input base is pushed onto the stack.
+No mechanism has been provided for the input of arbitrary
+numbers in bases less than 1 or greater than 16.
+.SH
+o
+.IP
+The top value on the stack is popped and used as the
+number radix for further output.
+If \fBo\fP is capitalized, the value of the output
+base is pushed onto the stack.
+.SH
+k
+.IP
+The top of the stack is popped, and that value is used as
+a scale factor
+that influences the number of decimal places
+that are maintained during multiplication, division, and exponentiation.
+The scale factor must be greater than or equal to zero and
+less than 100.
+If \fBk\fP is capitalized, the value of the scale factor
+is pushed onto the stack.
+.SH
+z
+.IP
+The value of the stack level is pushed onto the stack.
+.SH
+?
+.IP
+A line of input is taken from the input source (usually the console)
+and executed.
+.SH
+DETAILED DESCRIPTION
+.SH
+Internal Representation of Numbers
+.PP
+Numbers are stored internally using a dynamic storage allocator.
+Numbers are kept in the form of a string
+of digits to the base 100 stored one digit per byte
+(centennial digits).
+The string is stored with the low-order digit at the
+beginning of the string.
+For example, the representation of 157
+is 57,1.
+After any arithmetic operation on a number, care is taken
+that all digits are in the range 0\-99 and that
+the number has no leading zeros.
+The number zero is represented by the empty string.
+.PP
+Negative numbers are represented in the 100's complement
+notation, which is analogous to two's complement notation for binary
+numbers.
+The high order digit of a negative number is always \-1
+and all other digits are in the range 0\-99.
+The digit preceding the high order \-1 digit is never a 99.
+The representation of \-157 is 43,98,\-1.
+We shall call this the canonical form of a number.
+The advantage of this kind of representation of negative
+numbers is ease of addition.  When addition is performed digit
+by digit, the result is formally correct.  The result need only
+be modified, if necessary, to put it into canonical form.
+.PP
+Because the largest valid digit is 99 and the byte can
+hold numbers twice that large, addition can be carried out
+and the handling of carries done later when
+that is convenient, as it sometimes is.
+.PP
+An additional byte is stored with each number beyond
+the high order digit to indicate the number of
+assumed decimal digits after the decimal point.  The representation
+of .001 is 1,\fI3\fP
+where the scale has been italicized to emphasize the fact that it
+is not the high order digit.
+The value of this extra byte is called the
+.ft B
+scale factor
+.ft
+of the number.
+.SH
+The Allocator
+.PP
+DC uses a dynamic string storage allocator
+for all of its internal storage.
+All reading and writing of numbers internally is done through
+the allocator.
+Associated with each string in the allocator is a four-word header containing pointers
+to the beginning of the string, the end of the string,
+the next place to write, and the next place to read.
+Communication between the allocator and DC
+is done via pointers to these headers.
+.PP
+The allocator initially has one large string on a list
+of free strings.  All headers except the one pointing
+to this string are on a list of free headers.
+Requests for strings are made by size.
+The size of the string actually supplied is the next higher
+power of 2.
+When a request for a string is made, the allocator
+first checks the free list to see if there is
+a string of the desired size.
+If none is found, the allocator finds the next larger free string and splits it repeatedly until
+it has a string of the right size.
+Left-over strings are put on the free list.
+If there are no larger strings,
+the allocator tries to coalesce smaller free strings into
+larger ones.
+Since all strings are the result
+of splitting large strings,
+each string has a neighbor that is next to it in core
+and, if free, can be combined with it to make a string twice as long.
+This is an implementation of the `buddy system' of allocation
+described in [2].
+.PP
+Failing to find a string of the proper length after coalescing,
+the allocator asks the system for more space.
+The amount of space on the system is the only limitation
+on the size and number of strings in DC.
+If at any time in the process of trying to allocate a string, the allocator runs out of
+headers, it also asks the system for more space.
+.PP
+There are routines in the allocator for reading, writing, copying, rewinding,
+forward-spacing, and backspacing strings.
+All string manipulation is done using these routines.
+.PP
+The reading and writing routines
+increment the read pointer or write pointer so that
+the characters of a string are read or written in
+succession by a series of read or write calls.
+The write pointer is interpreted as the end of the
+information-containing portion of a string and a call
+to read beyond that point returns an end-of-string indication.
+An attempt to write beyond the end of a string
+causes the allocator to
+allocate a larger space and then copy
+the old string into the larger block.
+.SH
+Internal Arithmetic
+.PP
+All arithmetic operations are done on integers.
+The operands (or operand) needed for the operation are popped
+from the main stack and their scale factors stripped off.
+Zeros are added or digits removed as necessary to get
+a properly scaled result from the internal arithmetic routine.
+For example, if the scale of the operands is different and decimal
+alignment is required, as it is for
+addition, zeros are appended to the operand with the smaller
+scale.
+After performing the required arithmetic operation,
+the proper scale factor is appended to the end of the number before
+it is pushed on the stack.
+.PP
+A register called \fBscale\fP plays a part
+in the results of most arithmetic operations.
+\fBscale\fP is the bound on the number of decimal places retained in
+arithmetic computations.
+\fBscale\fP may be set to the number on the top of the stack
+truncated to an integer with the \fBk\fP command.
+\fBK\fP may be used to push the value of \fBscale\fP on the stack.
+\fBscale\fP must be greater than or equal to 0 and less than 100.
+The descriptions of the individual arithmetic operations will
+include the exact effect of \fBscale\fP on the computations.
+.SH
+Addition and Subtraction
+.PP
+The scales of the two numbers are compared and trailing
+zeros are supplied to the number with the lower scale to give both
+numbers the same scale.  The number with the smaller scale is
+multiplied by 10 if the difference of the scales is odd.
+The scale of the result is then set to the larger of the scales
+of the two operands.
+.PP
+Subtraction is performed by negating the number
+to be subtracted and proceeding as in addition.
+.PP
+Finally, the addition is performed digit by digit from the
+low order end of the number.  The carries are propagated
+in the usual way.
+The resulting number is brought into canonical form, which may
+require stripping of leading zeros, or for negative numbers
+replacing the high-order configuration 99,\-1 by the digit \-1.
+In any case, digits which are not in the range 0\-99 must
+be brought into that range, propagating any carries or borrows
+that result.
+.SH
+Multiplication
+.PP
+The scales are removed from the two operands and saved.
+The operands are both made positive.
+Then multiplication is performed in
+a digit by digit manner that exactly mimics the hand method
+of multiplying.
+The first number is multiplied by each digit of the second
+number, beginning with its low order digit.  The intermediate
+products are accumulated into a partial sum which becomes the
+final product.
+The product is put into the canonical form and its sign is
+computed from the signs of the original operands.
+.PP
+The scale of the result is set equal to the sum
+of the scales of the two operands.
+If that scale is larger than the internal register
+.ft B
+scale
+.ft
+and also larger than both of the scales of the two operands,
+then the scale of the result is set equal to the largest
+of these three last quantities.
+.SH
+Division
+.PP
+The scales are removed from the two operands.
+Zeros are appended or digits removed from the dividend to make
+the scale of the result of the integer division equal to
+the internal quantity
+\fBscale\fP.
+The signs are removed and saved.
+.PP
+Division is performed much as it would be done by hand.
+The difference of the lengths of the two numbers
+is computed.
+If the divisor is longer than the dividend,
+zero is returned.
+Otherwise the top digit of the divisor is divided into the top
+two digits of the dividend.
+The result is used as the first (high-order) digit of the
+quotient.
+It may turn out be one unit too low, but if it is, the next
+trial quotient will be larger than 99 and this will be
+adjusted at the end of the process.
+The trial digit is multiplied by the divisor and the result subtracted
+from the dividend and the process is repeated to get
+additional quotient digits until the remaining
+dividend is smaller than the divisor.
+At the end, the digits of the quotient are put into
+the canonical form, with propagation of carry as needed.
+The sign is set from the sign of the operands.
+.SH
+Remainder
+.PP
+The division routine is called and division is performed
+exactly as described.  The quantity returned is the remains of the
+dividend at the end of the divide process.
+Since division truncates toward zero, remainders have the same
+sign as the dividend.
+The scale of the remainder is set to 
+the maximum of the scale of the dividend and
+the scale of the quotient plus the scale of the divisor.
+.SH
+Square Root
+.PP
+The scale is stripped from the operand.
+Zeros are added if necessary to make the
+integer result have a scale that is the larger of
+the internal quantity
+\fBscale\fP
+and the scale of the operand.
+.PP
+The method used to compute sqrt(y) is Newton's method
+with successive approximations by the rule
+.EQ
+x sub {n+1} ~=~ half ( x sub n + y over x sub n )
+.EN
+The initial guess is found by taking the integer square root
+of the top two digits.
+.SH
+Exponentiation
+.PP
+Only exponents with zero scale factor are handled.  If the exponent is
+zero, then the result is 1.  If the exponent is negative, then
+it is made positive and the base is divided into one.  The scale
+of the base is removed.
+.PP
+The integer exponent is viewed as a binary number.
+The base is repeatedly squared and the result is
+obtained as a product of those powers of the base that
+correspond to the positions of the one-bits in the binary
+representation of the exponent.
+Enough digits of the result
+are removed to make the scale of the result the same as if the
+indicated multiplication had been performed.
+.SH
+Input Conversion and Base
+.PP
+Numbers are converted to the internal representation as they are read
+in.
+The scale stored with a number is simply the number of fractional digits input.
+Negative numbers are indicated by preceding the number with a \fB\_\fP (an 
+underscore).
+The hexadecimal digits A\-F correspond to the numbers 10\-15 regardless of input base.
+The \fBi\fP command can be used to change the base of the input numbers.
+This command pops the stack, truncates the resulting number to an integer,
+and uses it as the input base for all further input.
+The input base is initialized to 10 but may, for example be changed to
+8 or 16 to do octal or hexadecimal to decimal conversions.
+The command \fBI\fP will push the value of the input base on the stack.
+.SH
+Output Commands
+.PP
+The command \fBp\fP causes the top of the stack to be printed.
+It does not remove the top of the stack.
+All of the stack and internal registers can be output
+by typing the command \fBf\fP.
+The \fBo\fP command can be used to change the output base.
+This command uses the top of the stack, truncated to an integer as
+the base for all further output.
+The output base in initialized to 10.
+It will work correctly for any base.
+The command \fBO\fP pushes the value of the output base on the stack.
+.SH
+Output Format and Base
+.PP
+The input and output bases only affect
+the interpretation of numbers on input and output; they have no
+effect on arithmetic computations.
+Large numbers are output with 70 characters per line;
+a \\ indicates a continued line.
+All choices of input and output bases work correctly, although not all are
+useful.
+A particularly useful output base is 100000, which has the effect of
+grouping digits in fives.
+Bases of 8 and 16 can be used for decimal-octal or decimal-hexadecimal
+conversions.
+.SH
+Internal Registers
+.PP
+Numbers or strings may be stored in internal registers or loaded on the stack
+from registers with the commands \fBs\fP and \fBl\fP.
+The command \fBs\fIx\fR pops the top of the stack and
+stores the result in register \fBx\fP.
+\fIx\fP can be any character.
+\fBl\fIx\fR puts the contents of register \fBx\fP on the top of the stack.
+The \fBl\fP command has no effect on the contents of register \fIx\fP.
+The \fBs\fP command, however, is destructive.
+.SH
+Stack Commands
+.PP
+The command \fBc\fP clears the stack.
+The command \fBd\fP pushes a duplicate of the number on the top of the stack
+on the stack.
+The command \fBz\fP pushes the stack size on the stack.
+The command \fBX\fP replaces the number on the top of the stack
+with its scale factor.
+The command \fBZ\fP replaces the top of the stack
+with its length.
+.SH
+Subroutine Definitions and Calls
+.PP
+Enclosing a string in \fB[ ]\fP pushes the ascii string on the stack.
+The \fBq\fP command quits or in executing a string, pops the recursion levels by two.
+.SH
+Internal Registers \- Programming DC
+.PP
+The load and store
+commands together with \fB[ ]\fP to store strings, \fBx\fP to execute
+and the testing commands `<', `>', `=', `!<', `!>', `!=' can be used to program
+DC.
+The \fBx\fP command assumes the top of the stack is an string of DC commands
+and executes it.
+The testing commands compare the top two elements on the stack and if the relation holds, execute the register
+that follows the relation.
+For example, to print the numbers 0-9,
+.DS
+[lip1+  si  li10>a]sa
+0si  lax
+.DE
+.SH
+Push-Down Registers and Arrays
+.PP
+These commands were designed for used by a compiler, not by
+people.
+They involve push-down registers and arrays.
+In addition to the stack that commands work on, DC can be thought
+of as having individual stacks for each register.
+These registers are operated on by the commands \fBS\fP and \fBL\fP.
+\fBS\fIx\fR pushes the top value of the main stack onto the stack for
+the register \fIx\fP.
+\fBL\fIx\fR pops the stack for register \fIx\fP and puts the result on the main
+stack.
+The commands \fBs\fP and \fBl\fP also work on registers but not as push-down
+stacks.
+\fBl\fP doesn't effect the top of the
+register stack, and \fBs\fP destroys what was there before.
+.PP
+The commands to work on arrays are \fB:\fP and \fB;\fP.
+\fB:\fIx\fR pops the stack and uses this value as an index into
+the array \fIx\fP.
+The next element on the stack is stored at this index in \fIx\fP.
+An index must be greater than or equal to 0 and
+less than 2048.
+\fB;\fIx\fR is the command to load the main stack from the array \fIx\fP.
+The value on the top of the stack is the index
+into the array \fIx\fP of the value to be loaded.
+.SH
+Miscellaneous Commands
+.PP
+The command \fB!\fP interprets the rest of the line as a 
+.UX 
+command and passes it to 
+.UX
+to execute.
+One other compiler command is \fBQ\fP.
+This command uses the top of the stack as the number of levels of recursion to skip.
+.SH
+DESIGN CHOICES
+.PP
+The real reason for the use of a dynamic storage allocator was
+that a general purpose program could be (and in fact has been)
+used for a variety of other tasks.
+The allocator has some value for input and for compiling (i.e.
+the bracket [...] commands) where it cannot be known in advance
+how long a string will be.
+The result was that at a modest
+cost in execution time, all considerations of string allocation
+and sizes of strings were removed from the remainder of the program
+and debugging was made easier.  The allocation method
+used wastes approximately 25% of available space.
+.PP
+The choice of 100 as a base for internal arithmetic
+seemingly has no compelling advantage.  Yet the base cannot
+exceed 127 because of hardware limitations and at the cost
+of 5% in space, debugging was made a great deal easier and
+decimal output was made much faster.
+.PP
+The reason for a stack-type arithmetic design was
+to permit all DC commands from addition to subroutine execution
+to be implemented in essentially the same way.  The result
+was a considerable degree of logical separation of the final
+program into modules with very little communication between
+modules.
+.PP
+The rationale for the lack of interaction between the scale and the bases
+was to provide an understandable means of proceeding after
+a change of base or scale when numbers had already been entered.
+An earlier implementation which had global notions of
+scale and base did not work out well.
+If the value of
+.ft B
+scale
+.ft
+were to be interpreted in the current
+input or output base,
+then a change of base or scale in the midst of a
+computation would cause great confusion in the interpretation
+of the results.
+The current scheme has the advantage that the value of
+the input and output bases
+are only used for input and output, respectively, and they
+are ignored in all other operations.
+The value of
+scale
+is not used for any essential purpose by any part of the program
+and it is used only to prevent the number of
+decimal places resulting from the arithmetic operations from
+growing beyond all bounds.
+.PP
+The design rationale for the choices for the scales of
+the results of arithmetic were that in no case should
+any significant digits be thrown away if, on appearances, the
+user actually wanted them.  Thus, if the user wants
+to add the numbers 1.5 and 3.517, it seemed reasonable to give
+him the result 5.017 without requiring him to unnecessarily
+specify his rather obvious requirements for precision.
+.PP
+On the other hand, multiplication and exponentiation produce
+results with many more digits than their operands and it
+seemed reasonable to give as a minimum the number of decimal
+places in the operands but not to give more than that
+number of digits
+unless the user asked for them by specifying a value for \fBscale\fP.
+Square root can be handled in just the same way as multiplication.
+The operation of division gives arbitrarily many decimal places
+and there is simply no way to guess how many places the user
+wants.
+In this case only, the user must
+specify a \fBscale\fP to get any decimal places at all.
+.PP
+The scale of remainder was chosen to make it possible
+to recreate the dividend from the quotient and remainder.
+This is easy to implement; no digits are thrown away.
+.SH
+References
+.IP [1]
+L. L. Cherry, R. Morris,
+.ft I
+BC \- An Arbitrary Precision Desk-Calculator Language.
+.ft
+.IP [2]
+K. C. Knowlton,
+.ft I
+A Fast Storage Allocator,
+.ft
+Comm. ACM \fB8\fP, pp. 623-625 (Oct. 1965).
--- /dev/null
+++ usr.bin/dc/USD.doc/Makefile
@@ -0,0 +1,14 @@
+#	$OpenBSD: Makefile,v 1.2 2004/02/01 15:18:01 jmc Exp $
+#	$MidnightBSD: src/usr.bin/dc/USD.doc/Makefile,v 1.1 2007/08/25 18:43:21 archite Exp $
+
+DIR=	usd/05.dc
+SRCS=	dc
+MACROS=	-ms
+
+paper.ps: ${SRCS}
+	${EQN} ${SRCS} | ${ROFF} > ${.TARGET}
+
+paper.txt: ${SRCS}
+	${EQN} -Tascii ${SRCS} | ${ROFF} -Tascii > ${.TARGET}
+
+.include <bsd.doc.mk>


More information about the Midnightbsd-cvs mailing list