File:  [MW Coherent from dump] / coherent / d / bin / conv / conv.y
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/* conv - programmer's calculator
 * conv evaluates expressions in c style syntax and reports the results
 * in hexadecimal, decimal, octal, binary, and ascii character constants.
 * If arguments are present, they are each evaluated as independent
 * expressions, otherwise each line of standard input is evaluated.
 * Input numbers follow the style of the old conv, ie
 *	#digits	- hexadecimal
 *	0xdigits - hexadecimal
 *	0Xdigits - hexadecimal
 *	0digits - octal
 *	$digits - binary
 *	digits - decimal
 *	'character - ascii character constant
 * The only expressions not allowed are those involving arrays, pointers,
 * structure members, and addresses.  All of the integer arithmetic ops
 * are supported including variables, assignment ops, conditional expressions,
 * and the comma operator.
 * In addition, there is an iterative conditional expression
 *	<expr1> ?? <expr2> :: <expr3>
 * which evaluates to while (<expr1>) <expr2>; <expr3>, that is evaluating
 * <expr2> as often as <expr1> evaluates to true, then returning the value
 * of <expr3>.
 * Bug: function definition and evaluation should be permitted.
 */
%{
#include <ctype.h>

#define	NNODES	1000

char	*version = "Conv Version 2.00.\n";

typedef union yynode {
	struct {
		int	n_op;
		union yynode *n1_ln;
		union yynode *n1_rn;
	} yyn1;
	struct {
		int	n_op;
		long	n2_val;
	} yyn2;
	struct {
		char	n3_name[];
	} yyn3;
} NODE;
#define n_ln	yyn1.n1_ln
#define n_rn	yyn1.n1_rn
#define n_val	yyn2.n2_val
#define n_name	yyn3.n3_name

#define NULL ((NODE *)0)
NODE *node();
NODE *vnode();
NODE *nnode();
NODE *hash();
NODE *dotp;
long getcc();
long getv();

%}

%union {
	int	yy_op;
	long	yy_val;
	NODE	*yy_nod;
}

%start list

%token NUMBER NAME CALL LINK
%token INC DEC INCBEF DECBEF INCAFT DECAFT

%left ','
%right '=' ADDEQ SUBEQ MULEQ DIVEQ REMEQ ANDEQ IOREQ EOREQ SHLEQ SHREQ
%left QUQU COCO
%left '?' ':'
%left OR
%left AND
%left '|'
%left '^'
%left '&'
%left EQ NE
%left '<' '>' LE GE
%left SHL SHR
%left '+' '-'
%left '*' '/' '%'
%right '~' '!' UMINUS

%type <yy_op> '=' ADDEQ SUBEQ MULEQ DIVEQ REMEQ ANDEQ IOREQ EOREQ SHLEQ SHREQ
%type <yy_op> '?' ':' OR AND '|' '^' '&'
%type <yy_op> EQ NE '<' '>' LE GE
%type <yy_op> SHL SHR '+' '-' '*' '/' '%'
%type <yy_op> '~' '!' UMINUS '(' ')' ','
%type <yy_op> INC DEC INCAFT INCBEF DECAFT DECBEF
%type <yy_nod> NAME
%type <yy_val> NUMBER
%type <yy_nod> expr

%%

list:	/* empty */
|	list '\n'
|	list expr '\n' {
		eval($2, dotp->n_ln);
			switch ($2->n_op) {
		case IOREQ:
		case EOREQ:
		case ANDEQ:
		case SHLEQ:
		case SHREQ:
		case REMEQ:
		case DIVEQ:
		case MULEQ:
		case SUBEQ:
		case ADDEQ:
		case '=':
			break;
		default:
			putv(dotp->n_ln);
		}
		nfree($2);
	}
|	list error '\n' {
		yyerrok;
	}
;


expr:	expr ',' expr {
		$$ = node($2, $1, $3);
	}
|	NAME '=' expr {
		$$ = node($2, $1, $3);
	}
|	NAME ADDEQ expr {
		$$ = node($2, $1, $3);
	}
|	NAME SUBEQ expr {
		$$ = node($2, $1, $3);
	}
|	NAME MULEQ expr {
		$$ = node($2, $1, $3);
	}
|	NAME DIVEQ expr {
		$$ = node($2, $1, $3);
	}
|	NAME REMEQ expr {
		$$ = node($2, $1, $3);
	}
|	NAME ANDEQ expr {
		$$ = node($2, $1, $3);
	}
|	NAME IOREQ expr {
		$$ = node($2, $1, $3);
	}
|	NAME EOREQ expr {
		$$ = node($2, $1, $3);
	}
|	NAME SHLEQ expr {
		$$ = node($2, $1, $3);
	}
|	NAME SHREQ expr {
		$$ = node($2, $1, $3);
	}
|	NAME INC {
		$$ = node(INCAFT, $1, NULL);
	}
|	NAME DEC {
		$$ = node(DECAFT, $1, NULL);
	}
|	INC NAME {
		$$ = node(INCBEF, $2, NULL);
	}
|	DEC NAME {
		$$ = node(DECBEF, $2, NULL);
	}
|	expr QUQU expr COCO expr {
		$$ = node($2, $1, node($4, $3, $5));
	}
|	expr '?' expr ':' expr {
		$$ = node($2, $1, node($4, $3, $5));
	}
|	expr OR expr {
		$$ = node($2, $1, $3);
	}
|	expr AND expr {
		$$ = node($2, $1, $3);
	}
|	expr '|' expr {
		$$ = node($2, $1, $3);
	}
|	expr '^' expr {
		$$ = node($2, $1, $3);
	}
|	expr '&' expr {
		$$ = node($2, $1, $3);
	}
|	expr EQ expr {
		$$ = node($2, $1, $3);
	}
|	expr NE expr {
		$$ = node($2, $1, $3);
	}
|	expr '<' expr {
		$$ = node($2, $1, $3);
	}
|	expr '>' expr {
		$$ = node($2, $1, $3);
	}
|	expr LE expr {
		$$ = node($2, $1, $3);
	}
|	expr GE expr {
		$$ = node($2, $1, $3);
	}
|	expr SHR expr {
		$$ = node($2, $1, $3);
	}
|	expr SHL expr {
		$$ = node($2, $1, $3);
	}
|	expr '+' expr {
		$$ = node($2, $1, $3);
	}
|	expr '-' expr {
		$$ = node($2, $1, $3);
	}
|	expr '*' expr {
		$$ = node($2, $1, $3);
	}
|	expr '/' expr {
		$$ = node($2, $1, $3);
	}
|	expr '%' expr {
		$$ = node($2, $1, $3);
	}
|	'-' expr %prec UMINUS {
		$$ = node(UMINUS, $2, NULL);
	}
|	'~' expr %prec UMINUS {
		$$ = node($1, $2, NULL);
	}
|	'!' expr %prec UMINUS {
		$$ = node($1, $2, NULL);
	}
|	NAME {
		$$ = $1;
	}
|	NUMBER {
		$$ = vnode($1);
	}
|	'(' expr ')' {
		$$ = node($1, $2, NULL);
	}
;


%%

yylex()
{
	register int c;
	char *seq = "=";
	char tmpbuf[64];
	register char *p;

again:
	while ((c=getc()) == ' ' || c == '\t')
		;

	if (isalnum(c) || c == '#' || c == '$') {
		tmpbuf[0] = c;
		c = getc();
		for (p = tmpbuf+1; p < &tmpbuf[64] && isalnum(c); c = getc())
			*p++ = c;
		ungetc(c);
		*p++ = 0;
		c = tmpbuf[0];
		if (c == '#' || c == '$' || isdigit(c)) {
			yylval.yy_val = getv(tmpbuf);
			return (NUMBER);
		}
		yylval.yy_nod = hash(tmpbuf);
		return (NAME);
	}
	switch (c) {

	case '\'':
		yylval.yy_val = getcc();
		return NUMBER;
	case '\\': if (substr("\n", 1, 0))
			goto again;
		return yylval.yy_op = c;
	case '+': return substr("=+", ADDEQ, INC, c);
	case '-': return substr("=-", SUBEQ, DEC, c);
	case '*': return substr(seq, MULEQ, c);
	case '/': return substr(seq, DIVEQ, c);
	case '%': return substr(seq, REMEQ, c);
	case '&': return substr("=&", ANDEQ, AND, c);
	case '|': return substr("=|", IOREQ, OR, c);
	case '^': return substr(seq, EOREQ, c);
	case '=': return substr(seq, EQ, c);
	case '!': return substr(seq, NE, c);
	case '<': if ((c = substr("<=", SHL, LE, c)) == SHL)
			return substr(seq, SHLEQ, c);
		return yylval.yy_op = c;
	case '>': if ((c = substr(">=", SHR, GE, c)) == SHR)
			return substr(seq, SHREQ, c);
		return yylval.yy_op = c;
	case '.':
		yylval.yy_nod = dotp;
		return NAME;
	}
	return yylval.yy_op = c;
}

NODE *reg[32];

NODE *
hash(bp)
char *bp;
{
	int hash;
	{
		register char *p;
		register c;

		hash = 0;
		p = bp;
		while (c = *p++)
			hash += c;
	}
	{
		register NODE *rp, **ep;

		bp[sizeof(NODE)] = 0;
		for (ep = &reg[hash & 31]; rp = *ep; ep = &rp->n_rn) {
			if (strcmp(bp, rp->n_ln->n_rn->n_name) == 0)
				return (rp->n_ln);
		}
		rp = node(NAME, vnode((long) 0), nnode(bp));
		*ep = node(LINK, rp, NULL);
		return (rp);
	}
}

/*
 * Depending on the next character, return one of several tokens.
 */
substr(cp, t1)
register char *cp;
int t1;
{
	register int cn;
	register int *tp;

	tp = &t1;
	cn = getc();
	while (*cp)
		if (*cp++ == cn)
			return yylval.yy_op = *tp;
		else
			tp += 1;
	ungetc(cn);
	return yylval.yy_op = *tp;
}

int peekc;
char *inputs = 0;

getc()
{
	register int c;

	if (peekc) {
		c = peekc;
		peekc = 0;
	} else if (inputs != 0) {
		if (c = *inputs)
			inputs += 1;
		else
			c = -1;
	} else
		c = getchar();
	return c;
}

ungetc(c)
{
	peekc = c;
}

main(argc, argv)
char *argv[];
{
	dotp = node(NAME, vnode((long) 0), NULL);
	if (argc > 1) {
		while (--argc > 0) {
			++argv;
			if (!strcmp(*argv, "-V")) {
				printf(version);
				exit(0);
			}
			inputs = malloc(strlen(*argv)+2);
			strcpy(inputs, *argv);
			strcat(inputs, "\n");
			yyparse();
		}
	} else {
		inputs = 0;
		yyparse();
	}
	return 0;
}
yyerror() { puts("Syntax"); }

NODE _nodes_[NNODES];
NODE *_np_ = &_nodes_[0];

NODE *
alloc()
{
	register NODE *np;

	np = _np_;
	for (;;) {
		if (np->n_op == 0) {
			_np_ = np;
			return (np);
		}
		if (++np >= &_nodes_[NNODES])
			np = &_nodes_[0];
		if (np == _np_)
			break;
	}
	puts("No space");
	exit(1);
}

nfree(np)
register NODE *np;
{
	if (np->n_op != NAME && np->n_op != NUMBER) {
		if (np->n_rn != NULL)
			nfree(np->n_rn);
		nfree(np->n_ln);
	}
	if (np->n_op != NAME) {
		np->n_op = 0;
		if (np < _np_)
			_np_ = np;
	}
}

NODE *
node(op, nl, nr)
NODE *nl, *nr;
{
	register NODE *np;

	np = alloc();
	np->n_op = op;
	np->n_ln = nl;
	np->n_rn = nr;
	return (np);
}

NODE *
vnode(va)
long va;
{
	register NODE *np;

	np = alloc();
	np->n_op = NUMBER;
	np->n_val = va;
	return (np);
}

NODE *
nnode(cp)
register char *cp;
{
	register NODE *np;
	register char *p;

	np = alloc();
	p = np->n_name;
	while (p < np+1)
		*p++ = *cp++;
	return (np);
}

eval(np, dp)
register NODE *np, *dp;
{
	NODE lval, rval, *lptr;

	dp->n_op = NUMBER;
again:
	switch (np->n_op) {
	case '=':
	case ADDEQ:
	case SUBEQ:
	case MULEQ:
	case DIVEQ:
	case REMEQ:
	case SHREQ:
	case SHLEQ:
	case ANDEQ:
	case EOREQ:
	case IOREQ:
		eval(np->n_rn, &rval);
		/* Fall through */
	case INCBEF:
	case DECBEF:
	case INCAFT:
	case DECAFT:
		lptr = np->n_ln->n_ln;
		break;
	case NAME:
		lptr = np->n_ln;
		break;
	case ',':
	case '|':
	case '^':
	case '&':
	case EQ:
	case NE:
	case '<':
	case '>':
	case LE:
	case GE:
	case SHR:
	case SHL:
	case '+':
	case '-':
	case '*':
	case '/':
	case '%':
		eval(np->n_rn, &rval);
		/* Fall through */
	case UMINUS:
	case '~':
	case '!':
	case QUQU:
	case '?':
	case OR:
	case AND:
		eval(np->n_ln, &lval);
		break;
	case NUMBER:
		lptr = np;
		break;
	case '(':
		np = np->n_ln;
		goto again;
	default:
		printf("Bad operator: %d\n", np->n_op);
		return;
	}
	switch (np->n_op) {
	case ',':
		np = np->n_rn;
		goto again;
	case '=':
		lptr->n_val = rval.n_val;
		*dp = *lptr;
		break;
	case ADDEQ:
		lptr->n_val += rval.n_val;
		*dp = *lptr;
		break;
	case SUBEQ:
		lptr->n_val -= rval.n_val;
		*dp = *lptr;
		break;
	case MULEQ:
		lptr->n_val *= rval.n_val;
		*dp = *lptr;
		break;
	case DIVEQ:
		lptr->n_val /= rval.n_val;
		*dp = *lptr;
		break;
	case REMEQ:
		lptr->n_val %= rval.n_val;
		*dp = *lptr;
		break;
	case SHREQ:
		lptr->n_val >>= rval.n_val;
		*dp = *lptr;
		break;
	case SHLEQ:
		lptr->n_val <<= rval.n_val;
		*dp = *lptr;
		break;
	case ANDEQ:
		lptr->n_val &= rval.n_val;
		*dp = *lptr;
		break;
	case EOREQ:
		lptr->n_val ^= rval.n_val;
		*dp = *lptr;
		break;
	case IOREQ:
		lptr->n_val |= rval.n_val;
		*dp = *lptr;
		break;
	case INCBEF:
		++lptr->n_val;
		*dp = *lptr;
		break;
	case DECBEF:
		--lptr->n_val;
		*dp = *lptr;
		break;
	case INCAFT:
		*dp = *lptr;
		lptr->n_val++;
		break;
	case DECAFT:
		*dp = *lptr;
		lptr->n_val++;
		break;
	case NAME:
		*dp = *lptr;
		break;
	case NUMBER:
		*dp = *lptr;
		break;
	case '|':
		dp->n_val = lval.n_val | rval.n_val;
		break;
	case '^':
		dp->n_val = lval.n_val ^ rval.n_val;
		break;
	case '&':
		dp->n_val = lval.n_val & rval.n_val;
		break;
	case EQ:
		dp->n_val = lval.n_val == rval.n_val;
		break;
	case NE:
		dp->n_val = lval.n_val != rval.n_val;
		break;
	case '<':
		dp->n_val = lval.n_val < rval.n_val;
		break;
	case '>':
		dp->n_val = lval.n_val > rval.n_val;
		break;
	case LE:
		dp->n_val = lval.n_val <= rval.n_val;
		break;
	case GE:
		dp->n_val = lval.n_val >= rval.n_val;
		break;
	case SHR:
		dp->n_val = lval.n_val >> rval.n_val;
		break;
	case SHL:
		dp->n_val = lval.n_val << rval.n_val;
		break;
	case '+':
		dp->n_val = lval.n_val + rval.n_val;
		break;
	case '-':
		dp->n_val = lval.n_val - rval.n_val;
		break;
	case '*':
		dp->n_val = lval.n_val * rval.n_val;
		break;
	case '/':
		dp->n_val = lval.n_val / rval.n_val;
		break;
	case '%':
		dp->n_val = lval.n_val % rval.n_val;
		break;
	case UMINUS:
		dp->n_val = - lval.n_val;
		break;
	case '~':
		dp->n_val = ~ lval.n_val;
		break;
	case '!':
		dp->n_val = ! lval.n_val;
		break;
	case QUQU:
		if (lval.n_val)
			eval(np->n_rn->n_ln, &rval);
		else
			np = np->n_rn->n_rn;
		goto again;
	case '?':
		if (lval.n_val)
			np = np->n_rn->n_ln;
		else
			np = np->n_rn->n_rn;
		goto again;
	case OR:
		if (lval.n_val != 0) {
			*dp = lval;
			break;
		}
		np = np->n_rn;
		goto again;
	case AND:
		if (lval.n_val == 0) {
			*dp = lval;
			break;
		}
		np = np->n_rn;
		goto again;
	}
}

long
getcc()
{
	register int c, d;
	c = getc();
	d = getc();
	if (d != '\'') ungetc(d);
	return c;
}

char digits[16] = "0123456789ABCDEF";

long
getv(dp)
register char *dp;
{
	register int d;
	register long v;
	register int b;

	v = 0;
	b = 10; d = *dp++;
	switch (d) {
	case '#': b = 16; d = *dp++; break;
	case '$': b = 2; d = *dp++; break;
	case '0': b = 8; d = *dp++;
		if (d == 'x' || d == 'X') {
			b = 16; d = *dp++;
		}
		break;
	}
	while ((isdigit(d) && (d -= '0') < b)
	    || (isupper(d) && (d += 10 - 'A') < b)
	    || (islower(d) && (d += 10 - 'a') < b)) {
		v = v * b + d;
		d = *dp++;
		if (d == 0)
			return v;
	}
	printf("Bad digit: 0%o\n", dp[-1]);
	return v;
}

putv(v) NODE *v;
{
	long	l;
	register	c;
	long		m;

	l = v->n_val;
	/*
	 * hex, decimal, octal
	 */
	printf( "#%X %D 0%O $", l, l, l);
	/*
	 * binary
	 */
	for (c=32, m=l; m; --c, m<<=1)
		if (m < 0)
			break;
	do {
		printf( m<0? "1": "0");
		m <<= 1;
	} while (--c);
	/*
	 * char
	 */
	printf( " '");
	if ((c=(char)l) < 0) {
		printf( "~");
		c &= 0177;
	}
	if (c<' ' || c=='\177') {
		printf( "^");
		if (c == '\177')
			c = '?';
		else
			c += '@';
	}
	printf( "%c'\n", c);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.