
/*
 * Convert a MACRO-11 programme from
 * tasteless upper case to tasteful dual
 * case. Try to to clever things with
 * names and comments.
 */
#include <stdio.h>

#define	NCPS	6
#define	NB	20
#define	NOCORE	(char *) -1
#define	LETTER	0
#define	DIGIT	1
#define	OTHER	2

struct	sym
{
	struct	sym *s_sp;
	char	s_id[NCPS];
};

struct	sym	*sym	= NULL;

char	*autab[] = {
	"i",
	"c",
	"unix",
	"eof",
	NULL
};

char	ctype[] = {
	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,
	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,
	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,
	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,
	OTHER,	OTHER,	OTHER,	OTHER,	LETTER,	OTHER,	OTHER,	OTHER,
	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	LETTER,	OTHER,
	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,
	DIGIT,	DIGIT,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,
	OTHER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
	LETTER,	LETTER,	LETTER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER,
	OTHER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
	LETTER,	LETTER,	LETTER,	OTHER,	OTHER,	OTHER,	OTHER,	OTHER
};

main(argc, argv)
char *argv[];
{
	register char *p, *q;
	register c;
	char b[NB], id[NCPS];

	while ((c = getchar()) != EOF) {
		if (c == ';') {
			heading();
			continue;
		}
		while (c != EOF && c != '\n') {
			if (c == ';')
				comment();
			else if (c == '<') {
				putchar(c);
				while ((c = getchar())!=EOF && c!='>')
					putchar(c);
				putchar('>');
			} else if (c == '\'') {
				putchar(c);
				if ((c = getchar()) != EOF)
					putchar(c);
			} else if (c == '\"') {
				putchar(c);
				if ((c = getchar()) != EOF) {
					putchar(c);
					if ((c = getchar()) != EOF)
						putchar(c);
				}
			} else if (ctype[c] == LETTER) {
				getid(c, id);
				if (eq(id, ".ascii") || eq(id, ".asciz"))
					ascii(id);
				else {
					p = b;
					while ((c=getchar())==' ' || c=='\t') {
						if (p >= &b[NB-1])
							error("Too much b!\n");
						*p++ = c;
					}
					if (c == '=')
						saveid(id);
					ungetc(c, stdin);
					putid(id);
					q = b;
					while (q < p)
						putchar(*q++);
				}
			} else {
				if (c >= 'A' && c <= 'Z')
					c += 'a'-'A';
				putchar(c);
			}
			c = getchar();
		}
		putchar('\n');
	}
}

heading()
{
	register char *p;
	register c, f;
	char b[NB];
	int s;

	f = 1;
	do {
		putchar(';');
		s = 0;
		while ((c = getchar())!=EOF && c!='\n') {
			s = 1;
			if (c == ' ' || c == '.') {
				putchar(c);
				if (c == '.')
					f = 1;
				continue;
			}
			p = b;
			do {
				if (p >= &b[NB-1])
					error("Too much b!\n");
				if (c >= 'A' && c <= 'Z')
					c += 'a'-'A';
				*p++ = c;
				c = getchar();
			} while (c!=EOF && c!='\n' && c!=' ' && c!='.');
			*p = '\0';
			ungetc(c, stdin);
			makedual(b, f);
			printf("%s", b);
			f = 0;
		}
		putchar('\n');
		if (s == 0)
			f = 1;
	} while ((c = getchar()) == ';');
	ungetc(c, stdin);
}

makedual(b, f)
register char *b;
{
	register char *p, **up;

	up = autab;
	while ((p = *up++) != NULL) {
		if (equal(b, p)) {
			makeupper(b);
			return;
		}
	}
	if (f && b[0]>='a' && b[0]<='z')
		b[0] -= 'a'-'A';
}

makeupper(p)
register char *p;
{
	register c;

	while ((c = *p) != '\0') {
		if (c >= 'a' && c <= 'z')
			*p -= 'a'-'A';
		++p;
	}
}

comment()
{
	register c;

	putchar(';');
	while ((c = getchar()) == ' ' || c == '\t')
		;
	if (c != '\n')
		putchar(' ');
	if (c >= 'a' && c <= 'z')
		c -= 'a'-'A';
	while (c != EOF && c != '\n') {
		putchar(c);
		if ((c = getchar()) >= 'A' && c <= 'Z')
			c += 'a'-'A';
	}
	ungetc(c, stdin);
}

getid(c, id)
register c;
char *id;
{
	register char *p;

	p = id;
	do {
		if (p < &id[NCPS]) {
			if (c >= 'A' && c <= 'Z')
				c += 'a'-'A';
			*p++ = c;
		}
	} while ((c = getchar())!=EOF && (ctype[c]==LETTER || ctype[c]==DIGIT));
	while (p < &id[NCPS])
		*p++ = '\0';
	ungetc(c, stdin);
}

upper(id)
register char *id;
{
	register struct sym *sp;

	if (id[1] == '.' || id[1] == '$')
		return (1);
	if (id[2] == '.' || id[2] == '$')
		return (1);
	sp = sym;
	while (sp != NULL) {
		if (eq(id, sp->s_id))
			return (1);
		sp = sp->s_sp;
	}
	return (0);
}

eq(a, b)
register char *a, *b;
{
	register n;

	n = NCPS;
	while (n--)
		if (*a++ != *b++)
			return (0);
	return (1);
}

putid(id)
char *id;
{
	register char *p;
	register c;

	if (upper(id)) {
		p = id;
		while (p < &id[NCPS] && (c = *p++) != '\0') {
			if (c >= 'a' && c <= 'z')
				c -= 'a'-'A';
			putchar(c);
		}
	} else
		printf("%.?s", NCPS, id);
}

ascii(id)
char *id;
{
	register c, d;

	putid(id);
	while ((c = getchar())!=EOF && c!='\n' && c!=';') {
		if (c == ' ' || c == '\t') {
			putchar(c);
			continue;
		}
		d = c;
		putchar(c);
		while ((c = getchar())!=EOF && c!='\n' && c!=d)
			putchar(c);
		if (c == d)
			putchar(c);
		else
			ungetc(c, stdin);
	}
	ungetc(c, stdin);
}

saveid(id)
char *id;
{
	register struct sym *np, *sp;

	sp = sym;
	while (sp != NULL) {
		if (eq(id, sp->s_id))
			return;
		sp = sp->s_sp;
	}
	np = alloc(sizeof(struct sym));
	if (np == NOCORE)
		error("Out of space!\n");
	np->s_sp = sym;
	sym = np;
	copy(np->s_id, id, NCPS);
}
