| #include <string.h> | #include <string.h> | ||||
| #include <ctype.h> | #include <ctype.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <stdarg.h> | |||||
| #include <time.h> | #include <time.h> | ||||
| #if HAVE_STDINT_H | #if HAVE_STDINT_H | ||||
| #include <stdint.h> | #include <stdint.h> | ||||
| fclose(f_report); | fclose(f_report); | ||||
| } | } | ||||
| static void error(const char *format, const char *string) | |||||
| static void error(const char *format, ...) | |||||
| { | { | ||||
| if (string == NULL) | |||||
| string = ""; | |||||
| va_list args; | |||||
| va_start(args, format); | |||||
| fprintf(f_errors, "%s(%d): ", current_fname, linenum-1); | fprintf(f_errors, "%s(%d): ", current_fname, linenum-1); | ||||
| fprintf(f_errors, format, string); | |||||
| vfprintf(f_errors, format, args); | |||||
| fprintf(f_errors, "\n"); | fprintf(f_errors, "\n"); | ||||
| error_count++; | error_count++; | ||||
| va_end(args); | |||||
| } | } | ||||
| static void Error(const char *string) | static void Error(const char *string) | ||||
| } | } | ||||
| if (!isdigit(*p)) { | if (!isdigit(*p)) { | ||||
| if ((type == tNUMBER) && (*p == '-')) | if ((type == tNUMBER) && (*p == '-')) | ||||
| error("Expected an unsigned number", NULL); | |||||
| error("Expected an unsigned number"); | |||||
| else | else | ||||
| error("Expected a number", NULL); | |||||
| error("Expected a number"); | |||||
| } | } | ||||
| while (isdigit(*p)) { | while (isdigit(*p)) { | ||||
| acc *= 10; | acc *= 10; | ||||
| { | { | ||||
| // Get a number, but restrict value to max | // Get a number, but restrict value to max | ||||
| int value; | int value; | ||||
| char msg[80]; | |||||
| value = NextItem(tNUMBER); | value = NextItem(tNUMBER); | ||||
| if (value > max) { | if (value > max) { | ||||
| sprintf(msg, "Value %d is greater than maximum %d", value, max); | |||||
| error(msg, NULL); | |||||
| error("Value %d is greater than maximum %d", value, max); | |||||
| value = max; | value = max; | ||||
| } | } | ||||
| return value; | return value; | ||||
| if ((control & 1) == 0) { | if ((control & 1) == 0) { | ||||
| if (!NextItem(tOPENBRACKET)) | if (!NextItem(tOPENBRACKET)) | ||||
| error("Expected '('", NULL); | |||||
| error("Expected '('"); | |||||
| } | } | ||||
| value = NextItem(type); | value = NextItem(type); | ||||
| return value; | return value; | ||||
| if (item_terminator != ')') | if (item_terminator != ')') | ||||
| error("Expected ')'", NULL); | |||||
| error("Expected ')'"); | |||||
| return value; | return value; | ||||
| } | } | ||||
| error("Resample command failed: %s", command); | error("Resample command failed: %s", command); | ||||
| resample_fails++; | resample_fails++; | ||||
| if (sr1 != samplerate_native) { | |||||
| sprintf(msg, "Can't resample (%d to %d): %s", sr1, samplerate_native, fname); | |||||
| error("%s", msg); | |||||
| } else | |||||
| if (sr1 != samplerate_native) | |||||
| error("Can't resample (%d to %d): %s", sr1, samplerate_native, fname); | |||||
| else | |||||
| error("WAV file is not mono: %s", fname); | error("WAV file is not mono: %s", fname); | ||||
| remove(fname_temp); | remove(fname_temp); | ||||
| return 0; | return 0; | ||||
| value = NextItemBrackets(tSIGNEDNUMBER, 1); | value = NextItemBrackets(tSIGNEDNUMBER, 1); | ||||
| if (value > 127) { | if (value > 127) { | ||||
| value = 127; | value = 127; | ||||
| error("Parameter > 127", NULL); | |||||
| error("Parameter > 127"); | |||||
| } | } | ||||
| if (value < -128) { | if (value < -128) { | ||||
| value = -128; | value = -128; | ||||
| error("Parameter < -128", NULL); | |||||
| error("Parameter < -128"); | |||||
| } | } | ||||
| } else { | } else { | ||||
| value = NextItemBrackets(tNUMBER, 1); | value = NextItemBrackets(tNUMBER, 1); | ||||
| if (value > 255) { | if (value > 255) { | ||||
| value = 255; | value = 255; | ||||
| error("Parameter > 255", NULL); | |||||
| error("Parameter > 255"); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| not_flag = 0; | not_flag = 0; | ||||
| word2 = 0; | word2 = 0; | ||||
| if (prog_out >= prog_out_max) { | if (prog_out >= prog_out_max) { | ||||
| error("Phoneme program too large", NULL); | |||||
| error("Phoneme program too large"); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| do { | do { | ||||
| data = NextItemBrackets(tNUMBER, brackets); | data = NextItemBrackets(tNUMBER, brackets); | ||||
| if (data > 7) | if (data > 7) | ||||
| error("Expected list of stress levels", NULL); | |||||
| error("Expected list of stress levels"); | |||||
| bitmap |= (1 << data); | bitmap |= (1 << data); | ||||
| brackets = 3; | brackets = 3; | ||||
| finish = 1; | finish = 1; | ||||
| break; | break; | ||||
| default: | default: | ||||
| error("Expected AND, OR, THEN", NULL); | |||||
| error("Expected AND, OR, THEN"); | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| prog_out--; | prog_out--; | ||||
| } else { | } else { | ||||
| if (offset > MAX_JUMP) | if (offset > MAX_JUMP) | ||||
| error("IF block is too long", NULL); | |||||
| error("IF block is too long"); | |||||
| *p = i_JUMP_FALSE + offset; | *p = i_JUMP_FALSE + offset; | ||||
| } | } | ||||
| if_stack[if_level].p_then = NULL; | if_stack[if_level].p_then = NULL; | ||||
| USHORT *p; | USHORT *p; | ||||
| if (if_level < 1) { | if (if_level < 1) { | ||||
| error("ELSE not expected", NULL); | |||||
| error("ELSE not expected"); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| int CompileElif(void) | int CompileElif(void) | ||||
| { | { | ||||
| if (if_level < 1) { | if (if_level < 1) { | ||||
| error("ELIF not expected", NULL); | |||||
| error("ELIF not expected"); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| int offset; | int offset; | ||||
| if (if_level < 1) { | if (if_level < 1) { | ||||
| error("ENDIF not expected", NULL); | |||||
| error("ENDIF not expected"); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| offset = prog_out - p; | offset = prog_out - p; | ||||
| if (offset > MAX_JUMP) | if (offset > MAX_JUMP) | ||||
| error("IF block is too long", NULL); | |||||
| error("IF block is too long"); | |||||
| *p = i_JUMP + offset; | *p = i_JUMP + offset; | ||||
| p -= chain; | p -= chain; | ||||
| } else { | } else { | ||||
| // declare a procedure | // declare a procedure | ||||
| if (n_procs >= N_PROCS) { | if (n_procs >= N_PROCS) { | ||||
| error("Too many procedures", NULL); | |||||
| error("Too many procedures"); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| strcpy(proc_names[n_procs], item_string); | strcpy(proc_names[n_procs], item_string); | ||||
| while (!endphoneme && !feof(f_in)) { | while (!endphoneme && !feof(f_in)) { | ||||
| if ((keyword = NextItem(tKEYWORD)) < 0) { | if ((keyword = NextItem(tKEYWORD)) < 0) { | ||||
| if (keyword == -2) { | if (keyword == -2) { | ||||
| error("Missing 'endphoneme' before end-of-file", NULL); // end of file | |||||
| error("Missing 'endphoneme' before end-of-file"); // end of file | |||||
| break; | break; | ||||
| } | } | ||||
| error("Bad keyword in phoneme definition '%s'", item_string); | error("Bad keyword in phoneme definition '%s'", item_string); | ||||
| if (phoneme_out->type == phVOWEL) | if (phoneme_out->type == phVOWEL) | ||||
| phoneme_out->end_type = phcode; | phoneme_out->end_type = phcode; | ||||
| else if (phcode != phoneme_out->start_type) | else if (phcode != phoneme_out->start_type) | ||||
| error("endtype must equal starttype for consonants", NULL); | |||||
| error("endtype must equal starttype for consonants"); | |||||
| break; | break; | ||||
| case kVOICINGSWITCH: | case kVOICINGSWITCH: | ||||
| phcode = NextItem(tPHONEMEMNEM); | phcode = NextItem(tPHONEMEMNEM); | ||||
| value = NextItem(tNUMBER); | value = NextItem(tNUMBER); | ||||
| phoneme_out->std_length = value; | phoneme_out->std_length = value; | ||||
| if (prog_out > prog_buf) { | if (prog_out > prog_buf) { | ||||
| error("stress phonemes can't contain program instructions", NULL); | |||||
| error("stress phonemes can't contain program instructions"); | |||||
| prog_out = prog_buf; | prog_out = prog_buf; | ||||
| } | } | ||||
| break; | break; | ||||
| case kENDPROCEDURE: | case kENDPROCEDURE: | ||||
| endphoneme = 1; | endphoneme = 1; | ||||
| if (if_level > 0) | if (if_level > 0) | ||||
| error("Missing ENDIF", NULL); | |||||
| error("Missing ENDIF"); | |||||
| if ((prog_out > prog_buf) && (if_stack[0].returned == 0)) | if ((prog_out > prog_buf) && (if_stack[0].returned == 0)) | ||||
| *prog_out++ = i_RETURN; | *prog_out++ = i_RETURN; | ||||
| break; | break; | ||||
| } | } | ||||
| if (endphoneme != 1) | if (endphoneme != 1) | ||||
| error("'endphoneme' not expected here", NULL); | |||||
| error("'endphoneme' not expected here"); | |||||
| if (compile_phoneme) { | if (compile_phoneme) { | ||||
| if (phoneme_out->type == phINVALID) { | if (phoneme_out->type == phINVALID) { | ||||
| error("Phoneme type is missing", NULL); | |||||
| error("Phoneme type is missing"); | |||||
| phoneme_out->type = 0; | phoneme_out->type = 0; | ||||
| } | } | ||||
| phoneme_out->phflags = place_articulation << 16; | phoneme_out->phflags = place_articulation << 16; | ||||
| // check that all referenced phonemes have been declared | // check that all referenced phonemes have been declared | ||||
| for (ix = 0; ix < n_phcodes; ix++) { | for (ix = 0; ix < n_phcodes; ix++) { | ||||
| if (phoneme_tab2[ix].type == phINVALID) { | if (phoneme_tab2[ix].type == phINVALID) { | ||||
| fprintf(f_errors, "%3d: Phoneme [%s] not declared, referenced at line %d\n", linenum, | |||||
| WordToString(phoneme_tab2[ix].mnemonic), (int)(phoneme_tab2[ix].program)); | |||||
| error("Phoneme [%s] not declared, referenced at line %d", | |||||
| WordToString(phoneme_tab2[ix].mnemonic), (int)(phoneme_tab2[ix].program)); | |||||
| error_count++; | error_count++; | ||||
| phoneme_tab2[ix].type = 0; // prevent the error message repeating | phoneme_tab2[ix].type = 0; // prevent the error message repeating | ||||
| } | } | ||||
| } | } | ||||
| if (p_equivalence > &equivalence_buf[sizeof(equivalence_buf) - 16]) { | if (p_equivalence > &equivalence_buf[sizeof(equivalence_buf) - 16]) { | ||||
| error("'equivalents' tables are too large", NULL); | |||||
| error("'equivalents' tables are too large"); | |||||
| break; | break; | ||||
| } | } | ||||