#include <stdio.h>
#ifdef vax
#include <ctype.h>
#endif vax

#define	isoctal(x)	(((x) & ~7) == '0')

#define	S_OUTSIDE	0	/* Outside of everything */
#define	S_MODULE	1	/* Inside a module */
#define	S_FORWARD	2	/* Inside a forward module */
#define	S_PROCEDURE	3	/* Inside a procedure */
#define	S_PROCESS	4	/* Inside a process */

char	*keywords[] = {
#define			 OTHER		0
			"FORWARD",
#define			 FORWARD	1
			"INTERFACE",
#define			 INTERFACE	2
			"DEVICE",
#define			 DEVICE		3
			"MODULE",
#define			 MODULE		4
			"PROCEDURE",
#define			 PROCEDURE	5
			"PROCESS",
#define			 PROCESS	6
			"END",
#define			 END		7
			NULL
			};

main(argc, argv)
int	argc;
char	*argv[];
{
extern char	_sobuf[];

if (argc < 2 || 3 < argc) {
	fprintf(stderr, "Usage: %s modula_file [output_file]\n", argv[0]);
	exit(-1);
	}
if (freopen(argv[1], "r", stdin) == NULL) {
	perror(argv[1]);
	exit(-2);
	}
if (argc == 3 && freopen(argv[2], "w", stdout) == NULL) {
	perror(argv[2]);
	exit(-3);
	}
setbuf(stdout, _sobuf);
return(scan(0, S_OUTSIDE, ""));
}

scan(depth, state, name)
int		depth;
register int	state;
char		*name;
{
register int	type = -1;
register char	*t;
char		token[64];
int		previous_type;
extern char	*getident();

/* fprintf(stderr, "scan(%d, %d, \"%s\")\n", depth, state, name); */
for (;;) {
	if ((t = getident(token)) == NULL) {
		if (depth != 0)
			fputs("Unexpected EOF\n", stderr);
		return(depth);
		}
	previous_type = type;
	type = match(t, keywords);
	if (state == S_OUTSIDE && (type < FORWARD || MODULE < type)) {
		fprintf(stderr, "Unexpected ident \"%s\" outside of everything\n", t);
		return(depth + 1);
		}
	if (type >= MODULE) {
		if ((t = getident(token)) == NULL) {
			if (depth != 0)
				fputs("Unexpected EOF\n", stderr);
			return(depth);
			}
		if (match(t, keywords) != OTHER) {
			if (type == END)
				ungetident(t);
			else {
				fprintf(stderr, "Unexpected keyword: %s\n", t);
				return(depth);
				}
			}
		else if (state == S_FORWARD) {
			if (type == END && strcmp(t, name) == 0) {
				show(depth - 1, previous_type, type, t);
				return(0);
				}
			}
		else switch (type) {
			case MODULE:
				show(depth, previous_type, type, t);
				if (previous_type != FORWARD)
					scan(depth + 1, S_MODULE, t);
				else
					scan(depth + 1, S_FORWARD, t);
				break;

			case PROCEDURE:
				show(depth, previous_type, type, t);
				scan(depth + 1, S_PROCEDURE, t);
				break;

			case PROCESS:
				show(depth, previous_type, type, t);
				scan(depth + 1, S_PROCESS, t);
				break;

			case END:
				if (strcmp(t, name) == 0) {
					show(depth - 1, previous_type, type, t);
					return(0);
					}
				break;

			default:
				fprintf(stderr, "Unexpected type %d at depth %d\n", type, depth);
				return(depth);
			}
		}
	}
}

 char *
getident(buf)
register char	*buf;
{
register char	*p;
register int	c, in_quote, in_octal;
extern char	lookahead[];

if (lookahead[0] != '\0') {
	strcpy(buf, lookahead);
	lookahead[0] = '\0';
	return(buf);
	}
p = buf;
in_quote = 0;
in_octal = 0;
for (;;) {
	if ((c = getchar()) == EOF)
		break;
	if (in_quote) {
		if (c == '\'')
			in_quote = 0;
		}
	else if (in_octal) {
		if (!isoctal(c)) {
			if (c != 'B' && c != 'C')
				ungetc(c, stdin);
			in_octal = 0;
			}
		}
	else {
		if (isalpha(c) || (p != buf && (isdigit(c) || c == '_')))
			*p++ = c;
		else if (p != buf) {
			ungetc(c, stdin);
			break;
			}
		else if (c == '\'')
			in_quote = 1;
		else if (isoctal(c))
			in_octal = 1;
		}
	}
if (p == buf)
	return(NULL);		/* Th-th-th-that's all, folks! */
else {
	*p = '\0';
	return(buf);		/* return an IDENT token */
	}
}

ungetident(ident)
char	*ident;
{
extern char	lookahead[];

if (lookahead[0] != '\0')
	fprintf(stderr, "Overwriting \"%s\" in lookahead buffer\n", lookahead);
strcpy(lookahead, ident);
}

match(string, list)
register char	*string, *list[];
{
register int	index;

for (index = 1; *list != NULL; index++)
	if (strcmp(string, *list++) == 0)
		return(index);
return(0);
}

show(depth, previous_type, type, name)
register int	depth, previous_type, type;
char		*name;
{
while (depth-- > 0)
	fputs("|\t", stdout);
if (type == MODULE && (previous_type == INTERFACE || previous_type == DEVICE))
	printf("%s ", keywords[previous_type - 1]);
printf("%s %s\n", keywords[type - 1], name);
}

char	lookahead[64];
