--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <ctype.h>
+
+// #define DEBUG
+#ifdef DEBUG
+ #define log(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)
+#else
+ #define log(...) do {;} while (0)
+#endif /* DEBUG*/
+
+#define HASH_TABLE_BITS 8
+#define HASH_TABLE_SIZE (1 << HASH_TABLE_BITS)
+
+/* number of executables seen so far */
+static int num_exe;
+
+struct hash_table_entry {
+ char *key;
+ /* only used for objecs, not for executables */
+ unsigned exe_bitmask;
+};
+
+static struct hash_table_entry exe_table[HASH_TABLE_SIZE];
+static struct hash_table_entry obj_table[HASH_TABLE_SIZE];
+
+/* no need for anything sophisticated here */
+static int hash_token(const char *tok)
+{
+ uint32_t tmp = 31415927;
+ const uint8_t *src = (typeof(src))tok;
+
+ for (; *src; src++) {
+ tmp *= 27182817;
+ tmp += *tok;
+ }
+ return tmp % HASH_TABLE_SIZE;
+}
+
+static inline bool slot_empty(int idx, struct hash_table_entry *table)
+{
+ return table[idx].key == NULL;
+}
+
+static char *safe_strdup(const char *str)
+{
+ char *result = strdup(str);
+ if (result)
+ return result;
+ errno = ENOMEM;
+ perror("strdup");
+ exit(EXIT_FAILURE);
+}
+
+static bool lookup(const char *tok, struct hash_table_entry *table, int *idx)
+{
+ int i, h = hash_token(tok);
+
+ for (i = 0; i < HASH_TABLE_SIZE; i++) {
+ *idx = (h + i) % HASH_TABLE_SIZE;
+ if (slot_empty(*idx, table))
+ return false;
+ if (!strcmp(table[*idx].key, tok))
+ return true;
+ }
+ log ("hash table full !?\n");
+ exit(EXIT_FAILURE);
+}
+
+static bool insert(const char *tok, struct hash_table_entry *table, int *idx)
+{
+ if (lookup(tok, table, idx))
+ return false; /* not inserted */
+ table[*idx].key = safe_strdup(tok);
+ return true;
+}
+
+static void process_token(char *tok)
+{
+ int idx;
+ size_t len = strlen(tok);
+
+ assert(len > 0);
+ if (tok[len - 1] == ':') {
+ tok[len - 1] = '\0';
+ if (insert(tok, exe_table, &idx)) { /* new exe */
+ log("exe #%d: '%s', idx: %d\n", num_exe, tok, idx);
+ num_exe++;
+ }
+ } else {
+ if (num_exe == 0) {
+ log("invalid input\n");
+ exit(EXIT_FAILURE);
+ }
+ insert(tok, obj_table, &idx);
+ obj_table[idx].exe_bitmask |= (1 << (num_exe - 1));
+ }
+}
+
+static void print_ss_enum(int idx)
+{
+ char *s = obj_table[idx].key;
+
+ printf("SS_ENUM(");
+ for (; *s; s++)
+ printf("%c", toupper(*s));
+ printf(");\n");
+}
+
+static void dump_bipolar(void)
+{
+ int i, j;
+
+ for (i = 0; i < HASH_TABLE_SIZE; i++) {
+ if (slot_empty(i, obj_table))
+ continue;
+ printf("#ifdef MAIN_INPUT_FILE_IS_%s\n", obj_table[i].key);
+ for (j = 0; j < HASH_TABLE_SIZE; j++) {
+ unsigned mi, mj;
+ if (slot_empty(j, obj_table))
+ continue;
+ mi = obj_table[i].exe_bitmask;
+ mj = obj_table[j].exe_bitmask;
+ if ((mi & mj) == mi)
+ print_ss_enum(j);
+ }
+ printf("#endif\n");
+ }
+}
+
+int main(void)
+{
+ int ret;
+
+ for (;;) {
+ char tok[100];
+ ret = scanf("%96s", tok);
+ if (ret != 1)
+ break;
+ process_token(tok);
+ }
+ dump_bipolar();
+ return 0;
+}