home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume2 / autopun / phoneme.c < prev    next >
C/C++ Source or Header  |  1987-11-25  |  9KB  |  453 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3.  
  4. #define DATA
  5. #include "phoneme.h"
  6. #undef DATA
  7.  
  8. /*
  9.  * xlate_line() - given an English-text phrase or word,
  10.  * Translate that thing into a phoneme-list.
  11.  *
  12.  * xlate_line() returns a pointer to the *static* resultant phoneme-list.
  13.  */
  14.  
  15. short *
  16. xlate_line(text)
  17. char *text;    /* English text to convert */
  18. {
  19.     static short phonelist[MAXPHONES];
  20.     char word[1 + MAXPHONES + 1];    /* the current parsed word    */
  21.     short *nxtphones;
  22.     char *dp;
  23.     short *xlate_word();
  24.  
  25.     nxtphones = phonelist;
  26.     word[0] = ' ';
  27.     while (*text) {
  28.     while (*text && !(isalpha(*text) || *text == '\'')) {
  29.         ++text;
  30.     }
  31.     dp = &word[1];
  32.     if (!*text) break;            /* Loop Exit */
  33.  
  34.     while (isalpha(*text) || *text == '\'') {
  35.         if (islower(*text)) {
  36.         *dp = toupper(*text);
  37.         } else {
  38.         *dp = *text;
  39.         }
  40.         ++dp, ++text;
  41.     }
  42.     *dp++ = ' ';
  43.     *dp = '\0';
  44.     nxtphones = xlate_word(word, nxtphones);
  45.     }
  46.     *nxtphones = P_end;
  47.     return(phonelist);
  48. }
  49.  
  50. /*
  51.  * xlate_word() - translate the given English word into a phoneme stream.
  52.  * The word has the following form:
  53.  *    ' [-A-Z']* '
  54.  * That is, it begins and ends with a space and it contains only
  55.  * upper-case letters, apostrophes, and hyphens.
  56.  */
  57.  
  58. short *        /* where to put any following phonemes (or a terminator) */
  59. xlate_word(word, phonedst)
  60. char *word;
  61. short *phonedst;    /* where to put the new phonemes    */
  62. {
  63.     char *apply1rule();
  64.     short *newphones;    /* array of phonemes to append */
  65.  
  66.     ++word; /* Skip the initial blank */
  67.     while (*word) {
  68.     word = apply1rule(word, &newphones);
  69.     while (*newphones != P_end) {
  70.         *phonedst++ = *newphones++;
  71.     }
  72.     }
  73.     return(phonedst);
  74. }
  75.  
  76. /*
  77.  * apply1rule() - apply the appropriate translation rule to the start of
  78.  * the word provided, setting a pointer to the resultant phonemes and
  79.  * returning a pointer to the unconverted part of the word.
  80.  */
  81.  
  82. char *        /* returns the place to convert next    */
  83. apply1rule(word, newphp)
  84. char *word;    /* the part of the word to start in    */
  85. short **newphp;    /* where to put a pointer to the set of translated phonemes */
  86. {
  87.     int rtype;        /* rule type to use                */
  88.     struct rule *rule;    /* the current rule being tested        */
  89.     register char *cp;    /* temp pointer for matching            */
  90.     register char *rem;    /* points to the first char past the match    */
  91.     static short firstcall = TRUE;    /* "first call to this routine"    */
  92.  
  93.     static short nosym = P_end;    /* an empty phoneme list        */
  94.  
  95.     if (firstcall) {
  96.     firstcall = FALSE;
  97.     ruleinit();
  98.     }
  99.  
  100.     if (isupper(*word)) {
  101.     rtype = (int) (*word - 'A') + RIDX_A;
  102.     } else {
  103.     rtype = RIDX_PUNC;
  104.     }
  105.     for (rule = Rules[rtype]; rule->match; ++rule) {
  106.     for (cp = rule->match, rem = word; *cp; cp++, rem++) {
  107.         if (*cp != *rem) break;
  108.     }
  109.     if (*cp) continue; /* failed to match */
  110.  
  111.     if (!leftmatch(rule->prefix, rule->preflen, word - 1)) continue;
  112.     if (!rightmatch(rule->suffix, rule->sufflen, rem)) continue;
  113.  
  114.     *newphp = rule->outsyms;
  115.     return(rem);
  116.     }
  117.  
  118.     fprintf(stderr, "Error: Can't find rule for: '%c' in \"%s\"\n",
  119.      *word, word);
  120.     *newphp = &nosym;
  121.     return(word + 1);    /* Skip the annoyance */
  122. }
  123.  
  124.  
  125. int
  126. leftmatch(pattern, patlen, context)
  127. char *pattern;    /* first char of pattern to match in text */
  128. short patlen;    /* strlen(pattern)    */
  129. char *context;    /* last char of text to be matched */
  130. {
  131.     char *pat;
  132.     char *text;
  133.     int count;
  134.  
  135.     if (!*pattern) return(TRUE);    /* null string matches any context */
  136.  
  137.     /* point to last character in pattern string */
  138.     count = patlen;
  139.     pat = pattern + (count - 1);
  140.  
  141.     text = context;
  142.  
  143.     for (; count > 0; pat--, count--) {
  144.     switch (*pat) {
  145.     case '\'':
  146.     case ' ':
  147.     case 'A':
  148.     case 'B':
  149.     case 'C':
  150.     case 'D':
  151.     case 'E':
  152.     case 'F':
  153.     case 'G':
  154.     case 'H':
  155.     case 'I':
  156.     case 'J':
  157.     case 'K':
  158.     case 'L':
  159.     case 'M':
  160.     case 'N':
  161.     case 'O':
  162.     case 'P':
  163.     case 'Q':
  164.     case 'R':
  165.     case 'S':
  166.     case 'T':
  167.     case 'U':
  168.     case 'V':
  169.     case 'W':
  170.     case 'X':
  171.     case 'Y':
  172.     case 'Z':
  173.         if (*pat != *text) return(FALSE);
  174.         text--;
  175.         continue;
  176.  
  177.     case '#':    /* One or more vowels */
  178.         if (!isvowel(*text)) return(FALSE);
  179.         text--;
  180.  
  181.         while (isvowel(*text)) text--;
  182.         break;
  183.  
  184.     case ':':    /* Zero or more consonants */
  185.         while (isconsonant(*text)) text--;
  186.         break;
  187.  
  188.     case '^':    /* One consonant */
  189.         if (!isconsonant(*text)) return(FALSE);
  190.         text--;
  191.         break;
  192.  
  193.     case '.':    /* B, D, V, G, J, L, M, N, R, W, Z */
  194. #ifdef NOTDEF
  195.         if (*text != 'B' && *text != 'D' && *text != 'V'
  196.           && *text != 'G' && *text != 'J' && *text != 'L'
  197.           && *text != 'M' && *text != 'N' && *text != 'R'
  198.           && *text != 'W' && *text != 'Z') {
  199.         return FALSE;
  200.         }
  201.         text--;
  202. #endif
  203.         switch (*text) {
  204.         case 'B':
  205.         case 'D':
  206.         case 'V':
  207.         case 'G':
  208.         case 'J':
  209.         case 'L':
  210.         case 'M':
  211.         case 'N':
  212.         case 'R':
  213.         case 'W':
  214.         case 'Z':
  215.         text--;
  216.         break;
  217.         default:
  218.         return(FALSE);
  219.         }
  220.         break;
  221.  
  222.     case '+':    /* E, I or Y (front vowel) */
  223. #ifdef NOTDEF
  224.         if (*text != 'E' && *text != 'I' && *text != 'Y') return FALSE;
  225.         text--;
  226. #endif
  227.         switch(*text) {
  228.         case 'E':
  229.         case 'I':
  230.         case 'Y':
  231.         text--;
  232.         break;
  233.         default:
  234.         return(FALSE);
  235.         }
  236.         break;
  237.  
  238.     default:
  239.         fprintf(stderr, "Bad char in left rule: '%c'\n", *pat);
  240.         return(FALSE);
  241.     }
  242.     }
  243.     return(TRUE);
  244. }
  245.  
  246.  
  247. int
  248. rightmatch(pattern, patlen, context)
  249. char *pattern;    /* first char of pattern to match in text */
  250. short patlen;    /* strlen(pattern) [ignored]        */
  251. char *context;    /* last char of text to be matched */
  252. {
  253.     char *pat;
  254.     char *text;
  255.  
  256.     if (!*pattern) return(TRUE);    /* null string matches any context */
  257.  
  258.     pat = pattern;
  259.     text = context;
  260.  
  261.     for (pat = pattern; *pat != '\0'; pat++) {
  262.     switch (*pat) {
  263.     case '\'':
  264.     case ' ':
  265.     case 'A':
  266.     case 'B':
  267.     case 'C':
  268.     case 'D':
  269.     case 'E':
  270.     case 'F':
  271.     case 'G':
  272.     case 'H':
  273.     case 'I':
  274.     case 'J':
  275.     case 'K':
  276.     case 'L':
  277.     case 'M':
  278.     case 'N':
  279.     case 'O':
  280.     case 'P':
  281.     case 'Q':
  282.     case 'R':
  283.     case 'S':
  284.     case 'T':
  285.     case 'U':
  286.     case 'V':
  287.     case 'W':
  288.     case 'X':
  289.     case 'Y':
  290.     case 'Z':
  291.         if (*pat != *text) return(FALSE);
  292.         text++;
  293.         continue;
  294.  
  295.     case '#':    /* One or more vowels */
  296.         if (!isvowel(*text)) return FALSE;
  297.         text++;
  298.  
  299.         while (isvowel(*text)) text++;
  300.         break;
  301.  
  302.     case ':':    /* Zero or more consonants */
  303.         while (isconsonant(*text)) text++;
  304.         break;
  305.  
  306.     case '^':    /* One consonant */
  307.         if (!isconsonant(*text)) return FALSE;
  308.         text++;
  309.         break;
  310.  
  311.     case '.':    /* B, D, V, G, J, L, M, N, R, W, Z */
  312. #ifdef NOTDEF
  313.         if (*text != 'B' && *text != 'D' && *text != 'V'
  314.           && *text != 'G' && *text != 'J' && *text != 'L'
  315.           && *text != 'M' && *text != 'N' && *text != 'R'
  316.           && *text != 'W' && *text != 'Z') {
  317.         return(FALSE);
  318.         }
  319.         text++;
  320. #endif
  321.         switch (*text) {
  322.         case 'B':
  323.         case 'D':
  324.         case 'V':
  325.         case 'G':
  326.         case 'J':
  327.         case 'L':
  328.         case 'M':
  329.         case 'N':
  330.         case 'R':
  331.         case 'W':
  332.         case 'Z':
  333.         text++;
  334.         break;
  335.         default:
  336.         return(FALSE);
  337.         }
  338.         break;
  339.  
  340.     case '+':    /* E, I or Y (front vowel) */
  341. #ifdef NOTDEF
  342.         if (*text != 'E' && *text != 'I' && *text != 'Y') return(FALSE);
  343.         text++;
  344. #endif
  345.         switch(*text) {
  346.         case 'E':
  347.         case 'I':
  348.         case 'Y':
  349.         text++;
  350.         break;
  351.         default:
  352.         return(FALSE);
  353.         }
  354.         break;
  355.  
  356.     case '%':    /* ER, E, ES, ED, ING, ELY (a suffix) */
  357.         if (*text == 'E') {
  358.         text++;
  359.         if (*text == 'L') {
  360.             text++;
  361.             if (*text == 'Y') {
  362.             text++;
  363.             break;
  364.             } else {
  365.             text--; /* Don't gobble L */
  366.             break;
  367.             }
  368.         } else if (*text == 'R' || *text == 'S' || *text == 'D') {
  369.             text++;
  370.         }
  371.         break;
  372.         } else if (*text == 'I') {
  373.         text++;
  374.         if (*text == 'N') {
  375.             text++;
  376.             if (*text == 'G') {
  377.             text++;
  378.             break;
  379.             }
  380.         }
  381.         return(FALSE);
  382.         }
  383.         return(FALSE);
  384.  
  385.     default:
  386.         fprintf(stderr, "Bad char in right rule:'%c'\n", *pat);
  387.         return(FALSE);
  388.     }
  389.     }
  390.     return(TRUE);
  391. }
  392.  
  393. /*
  394.  * ruleinit() - initialize the remaining fields of the phoneme rule table.
  395.  */
  396.  
  397. ruleinit()
  398. {
  399.     struct rule *rule;
  400.     int rtype;
  401.  
  402.     for (rtype = 0; rtype < RULECNT; ++rtype) {
  403.     for (rule = Rules[rtype]; rule->match; ++rule) {
  404.         rule->preflen = strlen(rule->prefix);
  405.         rule->sufflen = strlen(rule->suffix);
  406.     }
  407.     }
  408. }
  409.  
  410. int
  411. isvowel(chr)
  412. char chr;
  413. {
  414. #ifdef NOTDEF
  415.     return(chr == 'A' || chr == 'E' || chr == 'I' || chr == 'O' || chr == 'U');
  416. #endif
  417.     switch (chr) {
  418.     case 'A':
  419.     case 'E':
  420.     case 'I':
  421.     case 'O':
  422.     case 'U':
  423.     return(TRUE);
  424.     }
  425.     return(FALSE);
  426. }
  427.  
  428. int
  429. isconsonant(chr)
  430. char chr;
  431. {
  432.     return(isupper(chr) && !isvowel(chr));
  433. }
  434.  
  435. /*
  436.  * outphonemes() - output the given P_end-terminated array of phonemes.
  437.  */
  438.  
  439. outphonemes(php)
  440. short *php;        /* phoneme pointer    */
  441. {
  442.     while (*php != P_end) {
  443.     outstring(phochars[*php]);
  444.     ++php;
  445.     }
  446. }
  447.  
  448. outstring(string)
  449. char *string;
  450. {
  451.     while (*string != '\0') fputc(*string++, stderr);
  452. }
  453.