#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct lst {
	void *data;
	struct lst *next;
};

struct lst *lst_cons(struct lst *elem, struct lst *lst);

struct lst *lst_append(struct lst *a, struct lst *b);

struct lst *lst_reverse(struct lst *lst);

void *alloc(size_t n);

int add(const char *s, struct lst *translation);

struct lst *translate(const char *s);

// --- main -------------------------------------------------------------------

void *alloc(size_t n)
{
	void *r;

	if (!(r = malloc(n))) {
		fputs("malloc() failed\n", stderr);
		exit(EXIT_FAILURE);
	}
	return r;
}

void print(struct lst *tp, FILE *iop)
{
	while (tp) {
		fputs(tp->data, iop);
		fputs(tp->next ? ", " : "\n", iop);
		tp = tp->next;
	}
}

struct lst *new_translation(const char *s)
{
	struct lst *tp = alloc(sizeof *tp);

	strcpy(tp->data = alloc(strlen(s) + 1), s);
	return tp;
}

struct lst *tokenise(char *s, int n, FILE *iop)
{
	const char *delim = " \t\r\n";
	struct lst *lst = 0;

	while (fgets(s, n, iop)) {
		for (char *sp = strtok(s, delim); sp; sp = strtok(0, delim))
			lst = lst_cons(new_translation(sp), lst);
		if (lst)
			return lst_reverse(lst);
	}
	return 0;
}

int main(int argc, char *argv[])
{
	struct lst *lst;
	char buf[8192];
	FILE *iop;

	if (argc != 2 || !(iop = fopen(argv[1], "r"))) {
		fprintf(stderr, "usage: %s dictionary\n",
			argv[0] && argv[0][0] ? argv[0] : "translate");
		return EXIT_FAILURE;
	}
	while ((lst = tokenise(buf, sizeof buf, iop))) {
		if (!lst->next)
			fprintf(stderr, "%s: missing translation\n",
				(char *) lst->data);
		else if (add(lst->data, lst->next))
			fprintf(stderr, "%s: invalid word\n",
				(char *) lst->data);
		free(lst);
	}
	fclose(iop);
	while (scanf("%8191s", buf) == 1)
		print(translate(buf), stdout);
	return 0;
}

// -- trie --------------------------------------------------------------------

struct letter {
	struct lst *translation;
	struct letter *link[26];
};

static int chartoindex(char c)	// Assumes a sensible charset.
{
	return isalpha((unsigned char) c) ?
		tolower((unsigned char) c) - 'a' : -1;
}

static struct letter trie;

static struct letter *new_letter(void)
{
	struct letter *lp = alloc(sizeof *lp);

	for (int i = 0; i < sizeof lp->link / sizeof lp->link[0]; i++)
		lp->link[i] = 0;
	lp->translation = 0;
	return lp;
}

int add(const char *s, struct lst *translation)
{
	struct letter *tp = &trie;
	int i;

	while (*s) {
		if ((i = chartoindex(*s++)) < 0)
			return -1;
		if (!tp->link[i])
			tp->link[i] = new_letter();
		tp = tp->link[i];
	}
	tp->translation = lst_append(translation, tp->translation);
	return 0;
}

struct lst *translate(const char *s)
{
	struct letter *tp;
	int i;

	for (tp = &trie; *s && tp; tp = tp->link[i])
		if ((i = chartoindex(*s++)) < 0)
			return 0;
	return tp ? tp->translation : 0;
}

// --- list -------------------------------------------------------------------

struct lst *lst_cons(struct lst *elem, struct lst *lst)
{
	return elem->next = lst, elem;
}

struct lst *lst_append(struct lst *a, struct lst *b)
{
	struct lst *r;

	if (!a)
		return b;
	for (r = a; a->next; a = a->next)
		;
	a->next = b;
	return r;
}

struct lst *lst_reverse(struct lst *lst)
{
	struct lst *r, *next;

	for (r = 0; lst; lst = next) {
		next = lst->next;
		r = lst_cons(lst, r);
	}
	return r;
}
