commit 8c574583b1dd24977f7fba225b579a81060faefe Author: Ahmed Siam Date: Wed Aug 23 09:45:04 2023 +0300 i18n patch 1 diff --git a/.gitignore b/.gitignore index 0d47485..47caa16 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,10 @@ tests/run_tests.py rtx_config.h *~ src/__pycache__/* + +/.vscode/ +/locales/Makefile +/locales/Makefile.in +*.res +*.dat +/configure~ diff --git a/Makefile.am b/Makefile.am index e6192d5..72c457b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,13 @@ pkgconfigdir = $(libdir)/pkgconfig dist_pkgconfig_DATA = apertium-recursive.pc -SUBDIRS = src +SUBDIRS = src locales EXTRA_DIST=autogen.sh test: all (cd tests || exit && ./build_tests.py && chmod +x ./run_tests.py && ./run_tests.py) + +export LTTB_I18N_DATA=$(datadir)/lttoolbox/lttoolbox.dat +export LOCALES_DIR=$(datadir)/$(PACKAGE_NAME) +export APRC_I18N_DATA=$(LOCALES_DIR)/aprc.dat diff --git a/configure.ac b/configure.ac index c7a43ac..33db558 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,7 @@ AC_ARG_ENABLE(debug, * ) AC_MSG_ERROR("Invalid value ${enableval} for --enable-debug") ;; esac]) PKG_CHECK_MODULES([LTTOOLBOX], [lttoolbox >= required_lttoolbox_version]) +PKG_CHECK_MODULES(I18N, [i18n], CPPFLAGS="$CPPFLAGS $I18N_CFLAGS"; LIBS="$LIBS $I18N_LIBS") AC_SUBST(LTTOOLBOX_CFLAGS) AC_SUBST(LTTOOLBOX_LIBS) @@ -68,5 +69,5 @@ AC_CONFIG_FILES([ Makefile src/Makefile apertium-recursive.pc - ]) + locales/Makefile]) AC_OUTPUT diff --git a/locales/Makefile.am b/locales/Makefile.am new file mode 100644 index 0000000..d480ef9 --- /dev/null +++ b/locales/Makefile.am @@ -0,0 +1,7 @@ +aprc.dat: root.txt en.txt + genrb -d . root.txt en.txt + echo root.res en.res > package_list.txt + pkgdata -p aprc --mode archive -d . package_list.txt + +localesdir = $(LOCALES_DIR) +dist_locales_DATA = aprc.dat diff --git a/locales/en.txt b/locales/en.txt new file mode 100644 index 0000000..0bd10e4 --- /dev/null +++ b/locales/en.txt @@ -0,0 +1,2 @@ +en{ +} \ No newline at end of file diff --git a/locales/package_list.txt b/locales/package_list.txt new file mode 100644 index 0000000..d5134dd --- /dev/null +++ b/locales/package_list.txt @@ -0,0 +1 @@ +root.res en.res diff --git a/locales/root.txt b/locales/root.txt new file mode 100644 index 0000000..7dcd8d6 --- /dev/null +++ b/locales/root.txt @@ -0,0 +1,198 @@ +root{ + randpath_desc{"Usage: {program} transducer prefix\n"} + rtx_comp_desc{"{program}: compile .rtx files\n" + "USAGE: {program} [-e name] [-f] [-l file] [-s] [-S] [-h] rule_file bytecode_file\n" + "Options:\n"} + exclude_desc{"exclude a rule by name"} + lexical_desc{"load a file of lexicalized weights"} + summarize_desc{"print rules to stderr as \"output -> pattern\""} + stats_desc{"print statistics about rule file to stdout"} + help_desc{"show this help"} + + rtx_decomp_desc{"{program}: decompile a transfer bytecode file\n" + "USAGE: {program} [ -h ] [input_file [output_file]]\n" + "Options:\n"} + rtx_proc_desc{"{program}: perform structural transfer\n" + "USAGE: {program} [-a] [-t] [-z] [ -T | -b ] [ -m mode ] [ -e | -f | -r | -s ] bytecode_file [input_file [output_file]]\n" + "Options:\n"} + anaphora_desc{"expect coreference LUs from apertium-anaphora"} + both_desc{"print text (use with -T)"} + everything_desc{"print a complete trace of execution"} + filter_desc{"trace filterParseGraph()"} + filter2_desc{"filter branches more often"} + mode_desc{"set the mode of tree output, options are \'flat\', \'nest\', \'latex\', \'dot\', \'box\'"} + rules_desc{"print the rules that are being applied"} + steps_desc{"print the instructions executed by the stack machine"} + trx_desc{"mimic the behavior of apertium-transfer and apertium-interchunk"} + tree_desc{"print parse trees rather than apply output rules"} + null_flush_desc{"flush output on \\0"} + + in_file_on_line{"In file \"{file}\" on line {line}:"} + syntax_error{"Syntax error: {error}"} + usage{"USAGE: {usage}"} + + macro_invoked_by{"macro \"{macro}\", invoked by "} + error_in_rule{"Error in {macros} rule beginning on line {line} of {file}: {error}"} + + defaulting_to{"{vals}, defaulting to \"{def}\""} + + APRC1000{"ERROR APRC1000: That tree mode has not yet been implemented."} + APRC1001{"ERROR APRC1001: FST has features that are unknown to this version of lttoolbox - upgrade!"} + APRC1002{"ERROR APRC1002: Unable to access \"{file}\"."} + APRC1003{"ERROR APRC1003: Unable to read transducer."} + APRC1004{"ERROR APRC1004: No paths begin with that prefix."} + APRC1005{"WARNING APRC1005: Summary mode not available for XML."} + APRC1006{"ERROR APRC1006: Unexpected end of file."} + APRC1007{"ERROR APRC1007: unexpected space."} + APRC1008{"ERROR APRC1008: unexpected comment."} + APRC1009{"ERROR APRC1009: expected \"{check1}\" or \"{check2}\", found \"{token}\"."} + APRC1010{"ERROR APRC1010: expected \"{check}\", found \"{token}\"."} + APRC1011{"ERROR APRC1011: expected identifier, found \"{token}\"."} + APRC1012{"ERROR APRC1012: unable to parse weight: \"{token}\"."} + APRC1013{"ERROR APRC1013: Unexpected side name {side}."} + APRC1014{"ERROR APRC1014: SIDE_SOURCES list is empty."} + APRC1015{"ERROR APRC1015: empty tag order rule."} + APRC1016{"WARNING APRC1016: Tag-rewrite rule + APRC1017{"ERROR APRC1017: Redefinition of attribute category \"{category}\"."} + APRC1018{"ERROR APRC1018: Use of category \"{category}\" in set arithmetic before definition."} + APRC1019{"ERROR APRC1019: empty attribute list."} + APRC1020{"ERROR APRC1020: Chunk tags can only be accessed from output sections of reduction rules."} + APRC1021{"ERROR APRC1021: Macros can only access their single argument."} + APRC1022{"ERROR APRC1022: Clip source is out of bounds (position {position} requested, but rule has only {elements} elements in its pattern)."} + APRC1023{"ERROR APRC1023: literal value cannot have a side."} + APRC1024{"ERROR APRC1024: variable cannot have a side."} + APRC1025{"ERROR APRC1025: literal value cannot be rewritten."} + APRC1026{"ERROR APRC1026: variable cannot be rewritten."} + APRC1027{"ERROR APRC1027: Empty conditional."} + APRC1028{"ERROR APRC1028: Cannot negate string (I can't parse 'not a = b', use 'not (a = b)' or 'a not = b' instead)."} + APRC1029{"ERROR APRC1029: ANDs, ORs, and conditions don't come out evenly."} + APRC1030{"ERROR APRC1030: Expected operator, found condition."} + APRC1031{"ERROR APRC1031: Expected operator, found clip."} + APRC1032{"ERROR APRC1032: Unknown operator \"{operator}\"."} + APRC1033{"ERROR APRC1033: Cannot set the analysis clip source multiple times. (You have multiple % in your rule pattern)."} + APRC1034{"ERROR APRC1034: expected closing bracket after lemma category."} + APRC1035{"ERROR APRC1035: Rule is missing output (use quotes if you were trying to use | as a lemma)."} + APRC1036{"ERROR APRC1036: first tag in pattern element must be literal."} + APRC1037{"ERROR APRC1037: rule has multiple sources for attribute {attr}."} + APRC1038{"ERROR APRC1038: Cannot {verb} from within if statement."} + APRC1039{"ERROR APRC1039: Cannot {verb} first element."} + APRC1040{"ERROR APRC1040: Cannot {verb} to something in an if statement."} + APRC1041{"ERROR APRC1041: Cannot {verb} inside and outside of if statement and cannot {verb} first element."} + APRC1042{"ERROR APRC1042: Cannot {verb} to a blank."} + APRC1043{"ERROR APRC1043: % cannot be used on blanks."} + APRC1044{"ERROR APRC1044: Cannot output indexed blank because pattern is one element long and thus does not include blanks."} + APRC1045{"ERROR APRC1045: Position index of blank out of bounds, expected an integer from 1 to {num}."} + APRC1046{"WARNING APRC1046: Use of indexed blank on line {line} is deprecated."} + APRC1047{"ERROR APRC1047: There is no position 0."} + APRC1048{"ERROR APRC1048: There are only {elements} elements in the pattern."} + APRC1049{"ERROR APRC1049: Outputs in a macro must specify a pattern."} + APRC1050{"ERROR APRC1050: No macro name specified."} + APRC1051{"ERROR APRC1051: Interpolating a global variable does not make sense."} + APRC1052{"ERROR APRC1052: Using % with a global variable does not make sense."} + APRC1053{"ERROR APRC1053: % not supported on output literals with @. Use %lemma(pos)."} + APRC1054{"ERROR APRC1054: If statement must begin with \"if\"."} + APRC1055{"ERROR APRC1055: Always clause must be only clause."} + APRC1056{"ERROR APRC1056: Unknown statement: \"{statement}\"."} + APRC1057{"ERROR APRC1057: Nested chunks are currently not allowed."} + APRC1058{"ERROR APRC1058: Macros cannot generate entire chunks."} + APRC1059{"ERROR APRC1059: Global variables cannot be set to chunks."} + APRC1060{"ERROR APRC1060: Global variables must be set to single nodes."} + APRC1061{"ERROR APRC1061: Conditional non-chunk output current not possible."} + APRC1062{"ERROR APRC1062: If statement cannot be empty."} + APRC1063{"WARNING APRC1063: if statement without else in macro on line {line}.\n" + " This may fail to produce output and cause crashes at runtime."} + APRC1064{"ERROR APRC1064: Output grouping with [] only valid inside chunks."} + APRC1065{"ERROR APRC1065: Chunk names must be identifiers. (I think I'm parsing a reduction rule.)\n" + "If this error doesn't make sense to you, a common reason is that on the line before this you have ; instead of |"} + APRC1066{"ERROR APRC1066: empty pattern."} + APRC1067{"ERROR APRC1067: Chunk index for setting source or reference is out of range."} + APRC1068{"ERROR APRC1068: Rule sets chunk source multiple times."} + APRC1069{"ERROR APRC1069: Rule sets chunk reference multiple times."} + APRC1070{"ERROR APRC1070: Rule sets global variable $${var} multiple times."} + APRC1071{"ERROR APRC1071: Rule sets global variable $%{var} multiple times."} + APRC1072{"ERROR APRC1072: rule has multiple sources for attribute {attr}."} + APRC1073{"ERROR APRC1073: Unexpected } in output pattern."} + APRC1074{"ERROR APRC1074: Output pattern does not have enough chunks."} + APRC1075{"WARNING APRC1075: Source category for tag-rewrite rule \"{src}\" > \"{dest}\" is undefined."} + APRC1076{"WARNING APRC1076: Destination category for tag-rewrite rule \"{src}\" > \"{dest}\" is undefined."} + APRC1077{"WARNING APRC1077: Tag-rewrite rule \"{src}\" > \"{dest}\" contains mapping from undefined category \"{cat}\"."} + APRC1078{"WARNING APRC1078: Tag-rewrite rule \"{src}\" > \"{dest}\" does not convert \"{a}\"."} + APRC1079{"WARNING APRC1079: Tag-rewrite rule \"{src}\" > \"{dest}\" converts \"{a}\" to multiple values:"} + APRC1080{"ERROR APRC1080: unknown attribute category \"{cat}\"."} + APRC1081{"ERROR APRC1081: Attempt to clip undefined attribute \"{attr}\"."} + APRC1082{"ERROR APRC1082: There is no tag-rewrite rule from \"{src}\" to \"{dest}\"."} + APRC1083{"ERROR APRC1083: Macro not given value for attribute \"{attr}\"."} + APRC1084{"ERROR APRC1084: could not find tag order for element {element}."} + APRC1085{"ERROR APRC1085: Could not find output pattern \"{pattern}\"."} + APRC1086{"ERROR APRC1086: Cannot find source for tag \"{pattern}\"."} + APRC1087{"ERROR APRC1087: Cannot evaluate AND with string as operand (try adding parentheses)."} + APRC1088{"ERROR APRC1088: Cannot evaluate OR with string as operand (try adding parentheses)."} + APRC1089{"ERROR APRC1089: Attempt to negate string value."} + APRC1090{"ERROR APRC1090: String operator cannot take condition as operand."} + APRC1091{"ERROR APRC1091: \"{element}\" is not an element of list \"{attr}\", so this check will always fail."} + APRC1092{"ERROR APRC1092: \"{optarg}\" is not a recognized tree mode. Valid options are \"flat\", \"nest\", \"latex\", \"dot\", and \"box\"."} + APRC1093{"ERROR APRC1093: tried to pop {type} but mode is {mode}."} + APRC1093_chunk_note{"The most common reason for getting below error is a macro that is missing an else clause."} + APRC1094{"ERROR APRC1094: Unknown StackElement mode {mode}."} + APRC1095{"ERROR APRC1095: Cannot CONCAT non-strings."} + APRC1096{"ERROR APRC1096: Cannot append non-string to chunk surface."} + APRC1097{"ERROR APRC1097: Cannot {action} to non-chunk."} + APRC1098{"ERROR APRC1098: Cannot APPENDSURFACESL to non-chunk."} + APRC1099{"ERROR APRC1099: Cannot DISTAG non-string."} + APRC1100{"ERROR APRC1100: Empty stack or top item is not chunk.\n" + "Check for conditionals that might not generate output\n" + "and ensure that lists of attributes are complete."} + APRC1101{"ERROR APRC1101: unknown instruction: {rule}"} + APRC1102{"ERROR APRC1102: Parse Error: Wordbound blank should be immediately followed by a Lexical Unit -> [[..]]^..$"} + APRC1103{"ERROR APRC1103: Expected attribute \"{attr}\"."} + APRC1104{"ERROR APRC1104: Cannot interpret empty pos attribute."} + APRC1105{"ERROR APRC1105: Position must be an integer."} + APRC1106{"ERROR APRC1106: Position {pos} is out of bounds."} + APRC1107{"ERROR APRC1107: Rule cannot have multiple s."} + APRC1108{"ERROR APRC1108: Unknown pattern \"{pattern}\"."} + APRC1109{"ERROR APRC1109: Rule cannot have empty pattern."} + APRC1110{"ERROR APRC1110: Rule cannot have multiple s."} + APRC1111{"ERROR APRC1111: Rule cannot have multiple s."} + APRC1112{"ERROR APRC1112: Rule must have ."} + APRC1113{"ERROR APRC1113: Rule must have ."} + APRC1114{"ERROR APRC1114: <{node}> cannot have more than two children."} + APRC1115{"ERROR APRC1115: <{node}> must have exactly two children."} + APRC1116{"ERROR APRC1116: Undefined variable \"{var}\"."} + APRC1117{"ERROR APRC1117: Unknown attribute \"{attr}\"."} + APRC1118{"ERROR APRC1118: Cannot set value of <{node}>."} + APRC1119{"ERROR APRC1119: Unknown macro \"{macro}\"."} + APRC1120{"ERROR APRC1120: Too many parameters, macro \"{macro}\" expects {expected}, got {given}."} + APRC1121{"ERROR APRC1121: Not enough parameters, macro \"{macro}\" expects {expected}, got {given}."} + APRC1122{"ERROR APRC1122: Unknown variable \"{var}\"."} + APRC1123{"ERROR APRC1123: Unrecognized statement \"{statement}\"."} + APRC1124{"ERROR APRC1124: cannot have multiple children."} + APRC1125{"ERROR APRC1125: cannot be empty."} + APRC1126{"ERROR APRC1126: can only contain s."} + APRC1127{"ERROR APRC1127: Unrecognized expression \"{exp}\"."} + APRC1128{"ERROR APRC1128: cannot have multiple children."} + APRC1130{"ERROR APRC1130: {node} cannot have more than two children."} + APRC1131{"ERROR APRC1131: Expected , found <{node}> instead."} + APRC1132{"ERROR APRC1132: Unknown list \"{list}\"."} + APRC1133{"ERROR APRC1133: Unrecognized condition \"{condition}\"."} + APRC1134{"ERROR APRC1134: Cannot have multiple s in a clause."} + APRC1135{"ERROR APRC1135: must have exactly one child."} + APRC1136{"ERROR APRC1136: cannot be empty."} + APRC1137{"ERROR APRC1137: clause must begin with ."} + APRC1138{"WARNING APRC1138: Disregarding non-integer position."} + APRC1139{"WARNING APRC1139: Disregarding out-of-bounds position."} + APRC1140{"WARNING APRC1140: Unexpected tag in {node} - ignoring"} + APRC1141{"WARNING APRC1141: Unexpected tag <{node}> in def-cat - ignoring"} + APRC1142{"WARNING APRC1142: Redefinition of pattern \"{pattern}\", using later value"} + APRC1143{"WARNING APRC1143: Redefinition of attribute \"{attr}\" - using later definition"} + APRC1144{"WARNING APRC1144: Redefinition of list \"{list}\" - using later definition"} + APRC1145{"WARNING APRC1145: Redefinition of macro \"{macro}\" - using later definition"} + APRC1146{"WARNING APRC1146: Ignoring elements except {element} in {node}."} + APRC1147{"WARNING APRC1147: Unknown element <{node}> in , ignoring."} + APRC1148{"WARNING APRC1148: Cannot set side \"{side}\", setting \"tl\" instead."} + APRC1149{"WARNING APRC1149: Unknown clip side \"{side}\", defaulting to \"tl\"."} + APRC1150{"WARNING APRC1150: Unknown side \"{side}\", defaulting to target."} + APRC1151{"WARNING APRC1151: Clauses after will not be executed."} + APRC1152{"WARNING APRC1152: Multiple clauses will not be executed."} + APRC1153{"WARNING APRC1153: Empty clause."} + APRC1154{"WARNING APRC1154: Ignoring unexpected clause in ."} +} diff --git a/src/Makefile.am b/src/Makefile.am index 1293423..21240fe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,6 @@ AM_LDFLAGS=$(LIBS) +AM_CPPFLAGS = -DAPRC_I18N_DATA='"$(APRC_I18N_DATA)"' -DLTTB_I18N_DATA='"$(LTTB_I18N_DATA)"' + bin_PROGRAMS = rtx-comp rtx-proc rtx-decomp random-path diff --git a/src/chunk.cc b/src/chunk.cc index 01682ec..c2b9430 100644 --- a/src/chunk.cc +++ b/src/chunk.cc @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -351,7 +352,7 @@ Chunk::writeTree(TreeMode mode, UFILE* out) } break; default: - cerr << "That tree mode has not yet been implemented." << endl; + I18n(APRC_I18N_DATA, "aprc").error("APRC1000", {}, {}, false);; } } diff --git a/src/randpath.cc b/src/randpath.cc index b8ae2da..159210e 100644 --- a/src/randpath.cc +++ b/src/randpath.cc @@ -8,6 +8,7 @@ #include #include #include +#include using namespace std; @@ -27,7 +28,7 @@ bool load(FILE* input) if (count == 4 && strncmp(header, HEADER_LTTOOLBOX, 4) == 0) { auto features = read_le(input); if (features >= LTF_UNKNOWN) { - throw std::runtime_error("FST has features that are unknown to this version of lttoolbox - upgrade!"); + I18n(APRC_I18N_DATA, "aprc").error("APRC1001", {}, {}, true); } } else { @@ -166,25 +167,25 @@ int main(int argc, char *argv[]) LtLocale::tryToSetLocale(); if(argc != 3) { - cerr << "Usage: " << argv[0] << " transducer prefix" << endl; + cerr << I18n(APRC_I18N_DATA, "aprc").format("randpath_desc", {"program"}, {argv[0]}); return EXIT_FAILURE; } FILE* tf = fopen(argv[1], "rb"); if(tf == NULL) { - cerr << "Unable to open " << argv[1] << " for reading." << endl; + I18n(APRC_I18N_DATA, "aprc").error("APRC1002", {"file"}, {argv[1]}, false); return EXIT_FAILURE; } if(!load(tf)) { - cerr << "Unable to read transducer." << endl; + I18n(APRC_I18N_DATA, "aprc").error("APRC1003", {}, {}, false); return EXIT_FAILURE; } prefix = to_ustring(argv[2]); generatePaths(); if(paths.size() == 0) { - cerr << "No paths begin with that prefix." << endl; + I18n(APRC_I18N_DATA, "aprc").error("APRC1004", {}, {}, false); return EXIT_FAILURE; } //seed_seq s (prefix.begin(), prefix.end()); diff --git a/src/rtx_comp.cc b/src/rtx_comp.cc index 4cfd409..03515f3 100644 --- a/src/rtx_comp.cc +++ b/src/rtx_comp.cc @@ -7,26 +7,26 @@ #include #include #include +#include using namespace std; void endProgram(char *name) { - cout << basename(name) << ": compile .rtx files" << endl; - cout << "USAGE: " << basename(name) << " [-e name] [-f] [-l file] [-s] [-S] [-h] rule_file bytecode_file" << endl; - cout << "Options:" << endl; + I18n i18n {APRC_I18N_DATA, "aprc"}; + cout << i18n.format("rtx_comp_desc", {"program"}, {basename(name)}); #if HAVE_GETOPT_LONG - cout << " -e, --exclude: exclude a rule by name" << endl; - cout << " -l, --lexical: load a file of lexicalized weights" << endl; - cout << " -s, --summarize: print rules to stderr as 'output -> pattern'" << endl; - cout << " -S, --stats: print statistics about rule file to stdout" << endl; - cout << " -h, --help: show this help" << endl; + cout << " -e, --exclude: " << i18n.format("exclude_desc") << endl; + cout << " -l, --lexical: " << i18n.format("lexical_desc") << endl; + cout << " -s, --summarize: " << i18n.format("summarize_desc") << endl; + cout << " -S, --stats: " << i18n.format("stats_desc") << endl; + cout << " -h, --help: " << i18n.format("help_desc") << endl; #else - cout << " -e: exclude a rule by name" << endl; - cout << " -l: load a file of lexicalized weights" << endl; - cout << " -s: print rules to stderr as 'output -> pattern'" << endl; - cout << " -S: print statistics about rule file to stdout" << endl; - cout << " -h: show this help" << endl; + cout << " -e: " << i18n.format("exclude_desc") << endl; + cout << " -l: " << i18n.format("lexical_desc") << endl; + cout << " -s: " << i18n.format("summarize_desc") << endl; + cout << " -S: " << i18n.format("stats_desc") << endl; + cout << " -h: " << i18n.format("help_desc") << endl; #endif exit(EXIT_FAILURE); } @@ -95,8 +95,7 @@ int main(int argc, char *argv[]) FILE* check = fopen(argv[optind], "r"); if(check == NULL) { - cout << "Unable to open " << argv[optind] << " for reading." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1002", {"file"}, {argv[optind]}, true); } int c; while((c = fgetc(check)) != '<') @@ -113,7 +112,7 @@ int main(int argc, char *argv[]) TRXCompiler comp; if(summary) { - cout << "Summary mode not available for XML." << endl; + I18n(APRC_I18N_DATA, "aprc").error("APRC1005", {}, {}, false); } for(auto lex : lexFiles) comp.loadLex(lex); for(auto exc : exclude) comp.excludeRule(exc); diff --git a/src/rtx_compiler.cc b/src/rtx_compiler.cc index 208c6ac..da0a701 100644 --- a/src/rtx_compiler.cc +++ b/src/rtx_compiler.cc @@ -2,6 +2,7 @@ #include #include #include +#include using namespace std; @@ -49,6 +50,40 @@ RTXCompiler::die(UString message) exit(EXIT_FAILURE); } +void +RTXCompiler::die(icu::UnicodeString message) +{ + I18n i18n {APRC_I18N_DATA, "aprc"}; + if(errorsAreSyntax) + { + cerr << i18n.format("in_file_on_line", {"file", "line"}, {sourceFile.c_str(), currentLine}) << endl; + cerr << i18n.format("syntax_error", {"error"}, {message}) << endl; + } + else + { + icu::UnicodeString macros; + while(macroNameStack.size() > 0) + { + macros += i18n.format("macro_invoked_by", {"macro"}, {icu::UnicodeString(macroNameStack.back().data())}); + macroNameStack.pop_back(); + } + cerr << i18n.format("error_in_rule", {"macros", "line", "file", "error"}, + {macros, currentRule->line, sourceFile.c_str(), message})<< endl; + } + if(errorsAreSyntax && !source.eof()) + { + UString arr = UString(recentlyRead.size()-2, ' '); + recentlyRead += unreadbuf; + while(!source.eof() && peekchar() != '\n') + { + recentlyRead += source.get(); + } + cerr << recentlyRead << endl; + cerr << arr << "^^^" << endl; + } + exit(EXIT_FAILURE); +} + UChar32 RTXCompiler::getchar() { @@ -126,7 +161,7 @@ RTXCompiler::nextTokenNoSpace() { if(source.eof()) { - die("Unexpected end of file"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1006")); } UChar32 c = getchar(); UChar32 next = peekchar(); @@ -146,11 +181,11 @@ RTXCompiler::nextTokenNoSpace() } else if(u_isspace(c)) { - die("unexpected space"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1007")); } else if(c == '!') { - die("unexpected comment"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1008")); } else if(c == '"') { @@ -159,7 +194,7 @@ RTXCompiler::nextTokenNoSpace() { if(next == '\\') next = getchar(); ret += next; - if(source.eof()) die("Unexpected end of file."_u); + if(source.eof()) die(I18n(APRC_I18N_DATA, "aprc").format("APRC1006")); next = getchar(); } } @@ -208,15 +243,22 @@ RTXCompiler::nextToken(UString check1 = ""_u, UString check2 = ""_u) } else if(!check1.empty() && !check2.empty()) { - die("expected '"_u + check1 + "' or '"_u + check2 + "', found '"_u + tok + "'"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1009", {"check1", "check2", "token"}, + {icu::UnicodeString(check1.data()), + icu::UnicodeString(check2.data()), + icu::UnicodeString(tok.data())})); } else if(!check1.empty()) { - die("expected '"_u + check1 + "', found '"_u + tok + "'"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1010", {"check", "token"}, + {icu::UnicodeString(check1.data()), + icu::UnicodeString(tok.data())})); } else { - die("expected '"_u + check2 + "', found '"_u + tok + "'"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1010", {"check", "token"}, + {icu::UnicodeString(check2.data()), + icu::UnicodeString(tok.data())})); } return tok; } @@ -237,7 +279,8 @@ RTXCompiler::parseIdent(bool prespace = false) } if(ret == "->"_u || (ret.size() == 1 && SPECIAL_CHARS.find(ret[0]) != string::npos)) { - die("expected identifier, found '"_u + ret + "'"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1011", {"token"}, + {icu::UnicodeString(ret.data())})); } return ret; } @@ -268,7 +311,8 @@ RTXCompiler::parseWeight() } catch(const invalid_argument& ia) { - die("unable to parse weight: "_u + ret); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1012", {"token"}, + {icu::UnicodeString(ret.data())})); } return r; } @@ -300,12 +344,13 @@ RTXCompiler::parseRule() } else if (side == "ref"_u) { clip_order.push_back(REFERENCECLIP); } else { - die("Unexpected side name "_u+side); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1013", {"side"}, + {icu::UnicodeString(side.data())})); } eatSpaces(); } if (clip_order.empty()) { - die("SIDE_SOURCES list is empty"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1014")); } reverse(clip_order.begin(), clip_order.end()); } else { @@ -361,7 +406,7 @@ RTXCompiler::parseOutputRule(UString pattern) } if(output.size() == 0) { - die("empty tag order rule"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1015")); } } outputRules[pattern] = output; @@ -397,7 +442,9 @@ RTXCompiler::parseRetagRule(UString srcTag) if(other[0].first == srcTag && other[0].second == destTag) { found = true; - cerr << "Warning: Tag-rewrite rule '" << srcTag << "' > '" << destTag << "' is defined multiple times. Mappings in earlier definition may be overwritten." << endl; + I18n(APRC_I18N_DATA, "aprc").error("APRC1016", {"src_tag", "dest_tag"}, + {icu::UnicodeString(srcTag.data()), + icu::UnicodeString(destTag.data())}, false); other.insert(other.begin()+1, rule.begin()+1, rule.end()); break; } @@ -419,7 +466,8 @@ RTXCompiler::parseAttrRule(UString categoryName) if(collections.find(categoryName) != collections.end() || PB.isAttrDefined(categoryName)) { - die("Redefinition of attribute category '"_u + categoryName + "'."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1017", {"category"}, + {icu::UnicodeString(categoryName.data())})); } eatSpaces(); if(isNextToken('(')) @@ -443,7 +491,8 @@ RTXCompiler::parseAttrRule(UString categoryName) UString other = parseIdent(true); if(collections.find(other) == collections.end()) { - die("Use of category '"_u + other + "' in set arithmetic before definition."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1018", {"category"}, + {icu::UnicodeString(other.data())})); } vector otherstuff = collections[other]; for(unsigned int i = 0; i < otherstuff.size(); i++) @@ -470,7 +519,7 @@ RTXCompiler::parseAttrRule(UString categoryName) } if(members.size() == 0) { - die("empty attribute list"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1019")); } collections.insert(pair>(categoryName, members)); noOverwrite.insert(pair>(categoryName, noOver)); @@ -523,7 +572,7 @@ RTXCompiler::parseClip(int src = -2) ret->src = ParentClip; if(currentLocType != LocTypeOutput) { - die("Chunk tags can only be accessed from output sections of reduction rules."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1020")); } } } @@ -552,12 +601,14 @@ RTXCompiler::parseClip(int src = -2) { if(ret->src == ParentClip || ret->src > 1) { - die("Macros can only access their single argument."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1021")); } } else if(bounds && src == -2 && ret->src > (int)currentRule->pattern.size()) { - die("Clip source is out of bounds (position "_u + StringUtils::itoa(ret->src) + " requested, but rule has only "_u + StringUtils::itoa(currentRule->pattern.size()) + " elements in its pattern)."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1022", {"position", "elements"}, + {ret->src, + to_string(currentRule->pattern.size()).c_str()})); } if(ret->src != StringVarClip) { @@ -567,11 +618,11 @@ RTXCompiler::parseClip(int src = -2) { if(ret->src == ConstantClip) { - die("literal value cannot have a side"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1023")); } else if(ret->src == StringVarClip) { - die("variable cannot have a side"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1024")); } ret->side = parseIdent(); } @@ -583,11 +634,11 @@ RTXCompiler::parseClip(int src = -2) { if(ret->src == ConstantClip) { - die("literal value cannot be rewritten"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1025")); } else if(ret->src == ParentClip || ret->src == StringVarClip) { - die("variable cannot be rewritten"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1026")); } ret->rewrite.push_back(parseIdent()); } @@ -632,7 +683,7 @@ RTXCompiler::parseCond() eatSpaces(); } nextToken(")"_u); - if(parts.size() == 0) die("Empty conditional."_u); + if(parts.size() == 0) die(I18n(APRC_I18N_DATA, "aprc").format("APRC1027")); vector> denot; bool negated = false; for(unsigned int i = 0; i < parts.size(); i++) @@ -663,7 +714,7 @@ RTXCompiler::parseCond() { if(destring.back().first || denot[i+1].first) { - die("Cannot negate string (I can't parse 'not a = b', use 'not (a = b)' or 'a not = b' instead)."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1028")); } denot[i].second->left = destring.back().second; denot[i].second->right = denot[i+1].second; @@ -686,13 +737,14 @@ RTXCompiler::parseCond() ret->right = destring[0].second; } else ret = destring[0].second; - if(destring.size() % 2 == 0) die("ANDs, ORs, and conditions don't come out evenly."_u); + if(destring.size() % 2 == 0) die(I18n(APRC_I18N_DATA, "aprc").format("APRC1029")); for(unsigned int i = 1; i < destring.size(); i += 2) { - if(destring[i].second->op != 0) die("Expected operator, found condition."_u); - if(destring[i].second->val->src != 0) die("Expected operator, found clip."_u); + if(destring[i].second->op != 0) die(I18n(APRC_I18N_DATA, "aprc").format("APRC1030")); + if(destring[i].second->val->src != 0) die(I18n(APRC_I18N_DATA, "aprc").format("APRC1031")); UChar op = lookupOperator(destring[i].second->val->part); - if(op == 0) die("Unknown operator '"_u + destring[i].second->val->part + "'."_u); + if(op == 0) die(I18n(APRC_I18N_DATA, "aprc").format("APRC1031", {"operator"}, + {icu::UnicodeString(destring[i].second->val->part.data())})); Cond* temp = ret; ret = new Cond; ret->left = temp; @@ -722,7 +774,7 @@ RTXCompiler::parsePatternElement(Rule* rule) if(isNextToken('%')) { if(rule->grab_all != -1) { - die("Cannot set the analysis clip source multiple times. (You have multiple % in your rule pattern.)"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1033")); } rule->grab_all = rule->pattern.size()+1; } @@ -734,11 +786,11 @@ RTXCompiler::parsePatternElement(Rule* rule) else if(t1 == "["_u) { t1 = "$"_u + parseIdent(); - if(!isNextToken(']')) die("expected closing bracket after lemma category"_u); + if(!isNextToken(']')) die(I18n(APRC_I18N_DATA, "aprc").format("APRC1034")); } else if(t1 == "|"_u) { - die("Rule is missing output (use quotes if you were trying to use | as a lemma)"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1035")); } if(isNextToken('@')) { @@ -747,7 +799,7 @@ RTXCompiler::parsePatternElement(Rule* rule) } else if(t1[0] == '$') { - die("first tag in pattern element must be literal"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1036")); } else { @@ -766,7 +818,7 @@ RTXCompiler::parsePatternElement(Rule* rule) Clip* cl = parseClip(rule->pattern.size()+1); if(rule->vars.find(cl->part) != rule->vars.end()) { - die("rule has multiple sources for attribute "_u + cl->part); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1037", {"attr"}, {icu::UnicodeString(cl->part.data())})); } rule->vars[cl->part] = cl; } @@ -811,23 +863,23 @@ RTXCompiler::parseOutputElement() UString verb = (ret->conjoined ? "conjoin"_u : "interpolate"_u); if(currentChunk == NULL) { - die("Cannot "_u + verb + " from within if statement."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1038", {"verb"}, {icu::UnicodeString(verb.data())})); } if(currentChunk->children.size() == 0) { - die("Cannot "_u + verb + " first element."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1039", {"verb"}, {icu::UnicodeString(verb.data())})); } if(currentChunk->children.back()->conds.size() > 0) { - die("Cannot "_u + verb + " to something in an if statement."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1040", {"verb"}, {icu::UnicodeString(verb.data())})); } if(currentChunk->children.back()->chunks.size() == 0) { - die("Cannot "_u + verb + " inside and outside of if statement and cannot "_u + verb + " first element."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1041", {"verb"}, {icu::UnicodeString(verb.data())})); } if(currentChunk->children.back()->chunks[0]->mode == "_"_u) { - die("Cannot "_u + verb + " to a blank."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1042", {"verb"}, {icu::UnicodeString(verb.data())})); } eatSpaces(); if(ret->interpolated) currentChunk->children.back()->chunks[0]->nextConjoined = true; @@ -839,7 +891,7 @@ RTXCompiler::parseOutputElement() { if(ret->getall) { - die("% cannot be used on blanks"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1043")); } ret->mode = "_"_u; getchar(); @@ -848,13 +900,14 @@ RTXCompiler::parseOutputElement() ret->pos = parseInt(); if(currentRule->pattern.size() == 1) { - die("Cannot output indexed blank because pattern is one element long and thus does not include blanks."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1044")); } if(ret->pos < 1 || ret->pos >= currentRule->pattern.size()) { - die("Position index of blank out of bounds, expected an integer from 1 to "_u + StringUtils::itoa(currentRule->pattern.size()-1) + "."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1045", {"num"}, + {to_string(currentRule->pattern.size()-1).c_str()})); } - cerr << "Warning: Use of indexed blank on line " << currentLine << " is deprecated." << endl; + I18n(APRC_I18N_DATA, "aprc").error("APRC1046", {"line"}, {currentLine}, false); } else { @@ -867,11 +920,12 @@ RTXCompiler::parseOutputElement() ret->pos = parseInt(); if(ret->pos == 0) { - die("There is no position 0."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1047")); } else if(currentLocType != LocTypeMacro && !isInterp && ret->pos > currentRule->pattern.size()) { - die("There are only "_u + StringUtils::itoa(currentRule->pattern.size()) + " elements in the pattern."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1048", {"elements"}, + {to_string(currentRule->pattern.size()).c_str()})); } if(peekchar() == '(') { @@ -881,14 +935,14 @@ RTXCompiler::parseOutputElement() } else if(currentLocType == LocTypeMacro) { - die("Outputs in a macro must specify a pattern."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1049")); } } else if(isNextToken('*')) { if(peekchar() != '(') { - die("No macro name specified."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1050")); } nextToken("("_u); ret->pattern = parseIdent(true); @@ -898,8 +952,8 @@ RTXCompiler::parseOutputElement() } else if(isNextToken('$')) { - if(isInterp) die("Interpolating a global variable does not make sense."_u); - if(ret->getall) die("Using % with a global variable does not make sense."_u); + if(isInterp) die(I18n(APRC_I18N_DATA, "aprc").format("APRC1051")); + if(ret->getall) die(I18n(APRC_I18N_DATA, "aprc").format("APRC1052")); nextToken("$"_u); ret->mode = "$$"_u; ret->pattern = parseIdent(true); @@ -913,7 +967,7 @@ RTXCompiler::parseOutputElement() { if(ret->getall) { - die("% not supported on output literals with @. Use %lemma(pos)."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1053")); } ret->mode = "@"_u; while(true) @@ -1032,11 +1086,11 @@ RTXCompiler::parseOutputCond() mode = StringUtils::substitute(mode, "_"_u, ""_u); if(ret->conds.size() == 0 && mode != "if"_u && mode != "always"_u) { - die("If statement must begin with 'if'."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1054")); } if(ret->conds.size() > 0 && mode == "always"_u) { - die("Always clause must be only clause."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1055")); } if(mode == "if"_u || mode == "elif"_u || mode == "elseif"_u) { @@ -1048,7 +1102,7 @@ RTXCompiler::parseOutputCond() } else if(mode != "else"_u && mode != "otherwise"_u && mode != "always"_u) { - die("Unknown statement: '"_u + mode + "'."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1056", {"statement"}, {icu::UnicodeString(mode.data())})); } eatSpaces(); if(peekchar() == '(') @@ -1067,15 +1121,15 @@ RTXCompiler::parseOutputCond() { if(currentLoc == LocChunk) { - die("Nested chunks are currently not allowed."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1057")); } else if(currentLocType == LocTypeMacro) { - die("Macros cannot generate entire chunks."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1058")); } else if(currentLoc == LocVarSet) { - die("Global variables cannot be set to chunks."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1059")); } ret->nest.push_back(NULL); ret->clips.push_back(NULL); @@ -1085,7 +1139,7 @@ RTXCompiler::parseOutputCond() { if(currentLoc == LocVarSet) { - die("Global variables must be set to single nodes."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1060")); } ret->nest.push_back(NULL); ret->clips.push_back(NULL); @@ -1095,7 +1149,7 @@ RTXCompiler::parseOutputCond() { if(currentLoc != LocChunk && currentLoc != LocVarSet) { - die("Conditional non-chunk output current not possible."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1061")); } ret->chunks.push_back(parseOutputElement()); ret->nest.push_back(NULL); @@ -1112,14 +1166,13 @@ RTXCompiler::parseOutputCond() currentClip = clipwas; if(ret->chunks.size() == 0) { - die("If statement cannot be empty."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1062")); } if(ret->conds.size() == ret->nest.size()) { if(currentLoc == LocChunk && currentLocType == LocTypeMacro) { - cerr << "Warning: if statement without else in macro on line " << currentLine << "." << endl; - cerr << " This may fail to produce output and cause crashes at runtime." << endl; + I18n(APRC_I18N_DATA, "aprc").error("APRC1063", {"line"}, {currentLine}, false); } //die("If statement has no else clause and thus could produce no output."_u); ret->nest.push_back(NULL); @@ -1161,7 +1214,7 @@ RTXCompiler::parseOutputChunk() { if(currentLoc != LocChunk) { - die("Output grouping with [] only valid inside chunks."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1064")); } ch->mode = "[]"_u; end = ']'; @@ -1203,7 +1256,7 @@ RTXCompiler::parseReduceRule(UString output, UString next) { if(SPECIAL_CHARS.find(cur) != UString::npos) { - die("Chunk names must be identifiers. (I think I'm parsing a reduction rule.)\nIf this error doesn't make sense to you, a common reason is that on the line before this you have ; instead of |"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1065")); } outNodes.push_back(cur); cur = nextToken(); @@ -1260,7 +1313,7 @@ RTXCompiler::parseReduceRule(UString output, UString next) } if(rule->pattern.size() == 0) { - die("empty pattern"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1066")); } eatSpaces(); if(isNextToken('?')) @@ -1282,7 +1335,7 @@ RTXCompiler::parseReduceRule(UString output, UString next) } if(idx == 0 || idx > outNodes.size()) { - die("Chunk index for setting source or reference is out of range."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1067")); } nextToken("/"_u); bool sl = (nextToken("sl"_u, "ref"_u) == "sl"_u); @@ -1295,7 +1348,7 @@ RTXCompiler::parseReduceRule(UString output, UString next) { if(rule->output_sl[idx-1] != NULL) { - die("Rule sets chunk source multiple times."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1068")); } rule->output_sl[idx-1] = cond; } @@ -1303,7 +1356,7 @@ RTXCompiler::parseReduceRule(UString output, UString next) { if(rule->output_ref[idx-1] != NULL) { - die("Rule sets chunk reference multiple times."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1069")); } rule->output_ref[idx-1] = cond; } @@ -1313,7 +1366,7 @@ RTXCompiler::parseReduceRule(UString output, UString next) UString var = parseIdent(); if(rule->globals.find(var) != rule->globals.end()) { - die("Rule sets global variable $$"_u + var + " multiple times."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1070", {"var"}, {icu::UnicodeString(var.data())})); } nextToken("="_u); currentLoc = LocVarSet; @@ -1331,7 +1384,7 @@ RTXCompiler::parseReduceRule(UString output, UString next) UString var = parseIdent(); if(rule->stringGlobals.find(var) != rule->stringGlobals.end()) { - die("Rule sets global variable $%"_u + var + " multiple times."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1071", {"var"}, {icu::UnicodeString(var.data())})); } nextToken("="_u); rule->stringGlobals[var] = parseClip(); @@ -1341,7 +1394,7 @@ RTXCompiler::parseReduceRule(UString output, UString next) UString var = parseIdent(); if(rule->vars.find(var) != rule->vars.end()) { - die("rule has multiple sources for attribute "_u + var); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1037", {"attr"}, {icu::UnicodeString(var.data())})); } nextToken("="_u); rule->vars[var] = parseClip(); @@ -1362,7 +1415,7 @@ RTXCompiler::parseReduceRule(UString output, UString next) while(chunk_count < rule->result.size()) { eatSpaces(); - if(source.eof()) die("Unexpected end of file."_u); + if(source.eof()) die(I18n(APRC_I18N_DATA, "aprc").format("APRC1006")); switch(peekchar()) { case '(': @@ -1379,11 +1432,11 @@ RTXCompiler::parseReduceRule(UString output, UString next) case '}': if(rule->result.size() == 1) { - die("Unexpected } in output pattern."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1073")); } else if(chunk_count < rule->result.size()) { - die("Output pattern does not have enough chunks."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1074")); } break; default: @@ -1415,12 +1468,14 @@ RTXCompiler::processRetagRules() UString dest = rule[0].second; if(!PB.isAttrDefined(src) && collections.find(src) == collections.end()) { - cerr << "Warning: Source category for tag-rewrite rule '" << src << "' > '" << dest << "' is undefined." << endl; + I18n(APRC_I18N_DATA, "aprc").error("APRC1075", {"src", "dest"}, + {icu::UnicodeString(src.data()), icu::UnicodeString(dest.data())}, false); continue; } if(!PB.isAttrDefined(dest) && collections.find(dest) == collections.end()) { - cerr << "Warning: Destination category for tag-rewrite rule '" << src << "' > '" << dest << "' is undefined." << endl; + I18n(APRC_I18N_DATA, "aprc").error("APRC1076", {"src", "dest"}, + {icu::UnicodeString(src.data()), icu::UnicodeString(dest.data())}, false); continue; } if(collections.find(src) == collections.end() || collections.find(dest) == collections.end()) continue; @@ -1431,7 +1486,8 @@ RTXCompiler::processRetagRules() UString cat = rule[i].first.substr(2); if(collections.find(cat) == collections.end()) { - cerr << "Warning: Tag-rewrite rule '" << src << "' > '" << dest << "' contains mapping from undefined category '" << cat << "'." << endl; + I18n(APRC_I18N_DATA, "aprc").error("APRC1077", {"src", "dest", "cat"}, + {icu::UnicodeString(src.data()), icu::UnicodeString(dest.data()), icu::UnicodeString(cat.data())}, false); continue; } for(auto v : collections[cat]) vals[v].push_back(rule[i].second); @@ -1458,14 +1514,19 @@ RTXCompiler::processRetagRules() } if(!found) { - cerr << "Warning: Tag-rewrite rule '" << src << "' > '" << dest << "' does not convert '" << a << "'." << endl; + I18n(APRC_I18N_DATA, "aprc").error("APRC1078", {"src", "dest", "a"}, + {icu::UnicodeString(src.data()), icu::UnicodeString(dest.data()), icu::UnicodeString(a.data())}, false); } } else if(vals[a].size() > 1) { - cerr << "Warning: Tag-rewrite rule '" << src << "' > '" << dest << "' converts '" << a << "' to multiple values: "; - for(auto b : vals[a]) cerr << "'" << b << "', "; - cerr << "defaulting to '" << vals[a][0] << "'." << endl; + icu::UnicodeString temp; + I18n(APRC_I18N_DATA, "aprc").error("APRC1079", {"src", "dest", "a"}, + {icu::UnicodeString(src.data()), icu::UnicodeString(dest.data()), icu::UnicodeString(a.data())}, false); + for(auto b : vals[a]) + temp += icu::UnicodeString(icu::UnicodeString(("\""_u + b + "\", "_u).data())); + cerr << I18n(APRC_I18N_DATA, "aprc").format("defaulting_to", {"vals", "def"}, + {temp, icu::UnicodeString(vals[a][0].data())}) << endl; } } } @@ -1493,7 +1554,7 @@ RTXCompiler::makePattern(int ruleid) tg = tg.substr(1, tg.size()-2); if(collections.find(tg) == collections.end()) { - die("unknown attribute category '"_u + tg + "'"_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1080", {"cat"}, {icu::UnicodeString(tg.data())})); } vector> tmp; for(auto tls : tags) @@ -1600,7 +1661,7 @@ RTXCompiler::compileClip(Clip* c, UString _dest = ""_u) if(c->src != 0 && !(c->part == "lemcase"_u || collections.find(c->part) != collections.end() || PB.isAttrDefined(c->part))) { - die("Attempt to clip undefined attribute '"_u + c->part + "'."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1081", {"attr"}, {icu::UnicodeString(c->part.data())})); } int src = (c->src == -1) ? 0 : c->src; bool useReplace = (currentLocType == LocTypeOutput); @@ -1735,7 +1796,8 @@ RTXCompiler::compileClip(Clip* c, UString _dest = ""_u) ret += DISTAG; return ret; } - die("There is no tag-rewrite rule from '"_u + src_cat + "' to '"_u + dest + "'."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1082", {"src", "dest"}, + {icu::UnicodeString(src_cat.data()), icu::UnicodeString(dest.data())})); } UString check; for(unsigned int i = 1; i < rule.size(); i++) @@ -1815,7 +1877,7 @@ RTXCompiler::processMacroClip(Clip* mac, OutputChunk* arg) } else { - die("Macro not given value for attribute '"_u + mac->part + "'."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1083", {"attr"}, {icu::UnicodeString(mac->part.data())})); } } else ret->src = arg->pos; @@ -1956,7 +2018,7 @@ RTXCompiler::processOutputChunk(OutputChunk* r) { if(currentRule->pattern[r->pos-1].size() < 2) { - die("could not find tag order for element "_u + StringUtils::itoa(r->pos)); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1084", {"element"}, {to_string(r->pos).c_str()})); } pos = currentRule->pattern[r->pos-1][1]; } @@ -1971,7 +2033,7 @@ RTXCompiler::processOutputChunk(OutputChunk* r) ret += OUTPUT; return ret; } - die("Could not find output pattern '"_u + patname + "'."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1085", {"pattern"}, {icu::UnicodeString(patname.data())})); } vector pattern = outputRules[patname]; @@ -2141,7 +2203,7 @@ RTXCompiler::processOutputChunk(OutputChunk* r) } else if(r->pos == 0) { - die("Cannot find source for tag '"_u + pattern[i] + "'."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1086", {"pattern"}, {icu::UnicodeString(pattern[i].data())})); } else { @@ -2253,26 +2315,26 @@ RTXCompiler::processCond(Cond* cond) { if(cond->left->op == 0 || cond->right->op == 0) { - die("Cannot evaluate AND with string as operand (try adding parentheses)."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1087")); } } else if(cond->op == OR) { if(cond->left->op == 0 || cond->right->op == 0) { - die("Cannot evaluate OR with string as operand (try adding parentheses)."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1088")); } } else if(cond->op == NOT) { if(cond->right->op == 0) { - die("Attempt to negate string value."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1089")); } } else if(cond->op != 0 && (cond->left->op != 0 || cond->right->op != 0)) { - die("String operator cannot take condition as operand."_u); + die(I18n(APRC_I18N_DATA, "aprc").format("APRC1090")); } else if(cond->op == EQUAL) { @@ -2305,7 +2367,8 @@ RTXCompiler::processCond(Cond* cond) break; } } - if(!found) die("'"_u + lit + "' is not an element of list '"_u + attr + "', so this check will always fail."_u); + if(!found) die(I18n(APRC_I18N_DATA, "aprc").format("APRC1091", {"element", "attr"}, + {icu::UnicodeString(lit.data()), icu::UnicodeString(attr.data())})); } } if(cond->op == 0) @@ -2537,8 +2600,7 @@ RTXCompiler::write(const string &fname) FILE *out = fopen(fname.c_str(), "wb"); if(out == NULL) { - cerr << "Error: cannot open '" << fname << "' for writing" << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1002", {"file"}, {fname.c_str()}, true); } vector> inRules; diff --git a/src/rtx_compiler.h b/src/rtx_compiler.h index 9222885..f0fdeeb 100644 --- a/src/rtx_compiler.h +++ b/src/rtx_compiler.h @@ -11,6 +11,7 @@ #include #include #include +#include using namespace std; @@ -292,6 +293,7 @@ private: * with a marker of the approximate location of the error */ void die(UString message); + void die(icu::UnicodeString message); ////////// // TOKENIZATION diff --git a/src/rtx_decomp.cc b/src/rtx_decomp.cc index e7858d4..7f9de96 100644 --- a/src/rtx_decomp.cc +++ b/src/rtx_decomp.cc @@ -9,16 +9,15 @@ #include #include #include +#include void endProgram(char *name) { - std::cout << basename(name) << ": decompile a transfer bytecode file" << std::endl; - std::cout << "USAGE: " << basename(name) << " [ -h ] [input_file [output_file]]" << std::endl; - std::cout << "Options:" << std::endl; + std::cout << I18n(APRC_I18N_DATA, "aprc").format("rtx_decomp_desc", {"program"}, {basename(name)}); #if HAVE_GETOPT_LONG - std::cout << " -h, --help: show this help" << std::endl; + std::cout << " -h, --help: " << I18n(APRC_I18N_DATA, "aprc").format("help_desc") << std::endl; #else - std::cout << " -h: show this help" << std::endl; + std::cout << " -h: " << I18n(APRC_I18N_DATA, "aprc").format("help_desc") << std::endl; #endif exit(EXIT_FAILURE); } @@ -263,8 +262,7 @@ int main(int argc, char *argv[]) in = fopen(argv[optind], "rb"); if(in == NULL) { - std::cerr << "Error: could not open file " << argv[optind] << " for reading." << std::endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1002", {"file"}, {argv[optind]}, true); } } if(optind <= (argc - 2)) @@ -272,8 +270,7 @@ int main(int argc, char *argv[]) out = u_fopen(argv[optind+1], "wb", NULL, NULL); if(out == NULL) { - std::cerr << "Error: could not open file " << argv[optind+1] << " for writing." << std::endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1002", {"file"}, {argv[optind + 1]}, true); } } diff --git a/src/rtx_proc.cc b/src/rtx_proc.cc index 63093cb..9d100f2 100644 --- a/src/rtx_proc.cc +++ b/src/rtx_proc.cc @@ -4,38 +4,38 @@ #include #include #include +#include void endProgram(char *name) { - cout << basename(name) << ": perform structural transfer" << endl; - cout << "USAGE: " << basename(name) << " [-a] [-t] [-z] [ -T | -b ] [ -m mode ] [ -e | -f | -r | -s ] bytecode_file [input_file [output_file]]" << endl; - cout << "Options:" << endl; + I18n i18n {APRC_I18N_DATA, "aprc"}; + cout << i18n.format("rtx_proc_desc"); #if HAVE_GETOPT_LONG - cout << " -a, --anaphora: expect coreference LUs from apertium-anaphora" << endl; - cout << " -b, --both: print text (use with -T)" << endl; - cout << " -e, --everything: print a complete trace of execution" << endl; - cout << " -f, --filter: trace filterParseGraph()" << endl; - cout << " -F, --filter: filter branches more often" << endl; - cout << " -m, --mode: set the mode of tree output, options are 'flat', 'nest', 'latex', 'dot', 'box'" << endl; - cout << " -r, --rules: print the rules that are being applied" << endl; - cout << " -s, --steps: print the instructions executed by the stack machine" << endl; - cout << " -t, --trx: mimic the behavior of apertium-transfer and apertium-interchunk" << endl; - cout << " -T, --tree: print parse trees rather than apply output rules" << endl; - cout << " -z, --null-flush: flush output on \\0" << endl; - cout << " -h, --help: show this help" << endl; + cout << " -a, --anaphora: " << i18n.format("anaphora_desc") << endl; + cout << " -b, --both: " << i18n.format("both_desc") << endl; + cout << " -e, --everything: " << i18n.format("everything_desc") << endl; + cout << " -f, --filter: " << i18n.format("filter_desc") << endl; + cout << " -F, --filter: " << i18n.format("filter2_desc") << endl; + cout << " -m, --mode: " << i18n.format("mode_desc") << endl; + cout << " -r, --rules: " << i18n.format("rules_desc") << endl; + cout << " -s, --steps: " << i18n.format("steps_desc") << endl; + cout << " -t, --trx: " << i18n.format("trx_desc") << endl; + cout << " -T, --tree: " << i18n.format("tree_desc") << endl; + cout << " -z, --null-flush: " << i18n.format("null_flush_desc") << endl; + cout << " -h, --help: " << i18n.format("help_desc") << endl; #else - cout << " -a: expect coreference LUs from apertium-anaphora" << endl; - cout << " -b: print text (use with -T)" << endl; - cout << " -e: print a complete trace of execution" << endl; - cout << " -f: trace filterParseGraph()" << endl; - cout << " -F: filter branches more often" << endl; - cout << " -m: set the mode of tree output, options are 'flat', 'nest', 'latex', 'dot', 'box'" << endl; - cout << " -r: print the rules that are being applied" << endl; - cout << " -s: print the instructions executed by the stack machine" << endl; - cout << " -t: mimic the behavior of apertium-transfer and apertium-interchunk" << endl; - cout << " -T: print parse trees rather than apply output rules" << endl; - cout << " -z: flush output on \\0" << endl; - cout << " -h: show this help" << endl; + cout << " -a: " << i18n.format("anaphora_desc") << endl; + cout << " -b: " << i18n.format("both_desc") << endl; + cout << " -e: " << i18n.format("everything_desc") << endl; + cout << " -f: " << i18n.format("filter_desc") << endl; + cout << " -F: " << i18n.format("filter2_desc") << endl; + cout << " -m: " << i18n.format("mode_desc") << endl; + cout << " -r: " << i18n.format("rules_desc") << endl; + cout << " -s: " << i18n.format("steps_desc") << endl; + cout << " -t: " << i18n.format("trx_desc") << endl; + cout << " -T: " << i18n.format("tree_desc") << endl; + cout << " -z: " << i18n.format("null_flush_desc") << endl; + cout << " -h: " << i18n.format("help_desc") << endl; #endif exit(EXIT_FAILURE); } @@ -104,8 +104,7 @@ int main(int argc, char *argv[]) case 'm': if(!p.setOutputMode(optarg)) { - cout << "\"" << optarg << "\" is not a recognized tree mode. Valid options are \"flat\", \"nest\", \"latex\", \"dot\", and \"box\"." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1092", {"optarg"}, {optarg}, true); } break; @@ -156,8 +155,7 @@ int main(int argc, char *argv[]) input = fopen(argv[optind+1], "rb"); if(input == NULL) { - cerr << "Unable to open " << argv[optind+1] << " for reading." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1002", {"file"}, {argv[optind+1]}, true); } } if(optind <= (argc - 3)) @@ -165,8 +163,7 @@ int main(int argc, char *argv[]) output = u_fopen(argv[optind+2], "w", NULL, NULL); if(input == NULL) { - cerr << "Unable to open " << argv[optind+2] << " for writing." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1002", {"file"}, {argv[optind+2]}, true); } } diff --git a/src/rtx_processor.cc b/src/rtx_processor.cc index 65532b4..717b70a 100644 --- a/src/rtx_processor.cc +++ b/src/rtx_processor.cc @@ -7,6 +7,7 @@ #include #include //#include +#include using namespace std; @@ -25,8 +26,7 @@ RTXProcessor::read(string const &filename) FILE *in = fopen(filename.c_str(), "rb"); if(in == NULL) { - cerr << "Unable to open file " << filename.c_str() << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1002", {"file"}, {filename.c_str()}, true); } longestPattern = 2*Compression::multibyte_read(in) - 1; @@ -167,8 +167,7 @@ RTXProcessor::popBool() } else { - cerr << "tried to pop bool but mode is " << theStack[stackIdx].mode << endl; - exit(1); + I18n(APRC_I18N_DATA, "aprc").error("APRC1093", {"type", "mode"}, {"bool", theStack[stackIdx].mode}, true); } } @@ -181,8 +180,7 @@ RTXProcessor::popInt() } else { - cerr << "tried to pop int but mode is " << theStack[stackIdx].mode << endl; - exit(1); + I18n(APRC_I18N_DATA, "aprc").error("APRC1093", {"type", "mode"}, {"int", theStack[stackIdx].mode}, true); } } @@ -199,8 +197,7 @@ RTXProcessor::popString() } else { - cerr << "tried to pop UString but mode is " << theStack[stackIdx].mode << endl; - exit(1); + I18n(APRC_I18N_DATA, "aprc").error("APRC1093", {"type", "mode"}, {"UString", theStack[stackIdx].mode}, true); } } @@ -217,8 +214,7 @@ RTXProcessor::popString(UString& dest) } else { - cerr << "tried to pop UString but mode is " << theStack[stackIdx].mode << endl; - exit(1); + I18n(APRC_I18N_DATA, "aprc").error("APRC1093", {"type", "mode"}, {"UString", theStack[stackIdx].mode}, true); } } @@ -231,9 +227,8 @@ RTXProcessor::popChunk() } else { - cerr << "tried to pop Chunk but mode is " << theStack[stackIdx].mode << endl; - cerr << "The most common reason for getting this error is a macro that is missing an else clause." << endl; - exit(1); + cerr << I18n(APRC_I18N_DATA, "aprc").format("APRC1093_chunk_note") << endl; + I18n(APRC_I18N_DATA, "aprc").error("APRC1093", {"type", "mode"}, {"Chunk", theStack[stackIdx].mode}, true); } } @@ -260,7 +255,7 @@ RTXProcessor::stackCopy(int src, int dest) theWblankStack[dest] = theWblankStack[src]; break; default: - cerr << "Unknown StackElement mode " << theStack[src].mode; + I18n(APRC_I18N_DATA, "aprc").error("APRC1094", {"mode"}, {theStack[src].mode}, false); break; } } @@ -752,8 +747,7 @@ RTXProcessor::applyRule(const UString& rule) { if(theStack[stackIdx].mode != 2 || theStack[stackIdx-1].mode != 2) { - cerr << "Cannot CONCAT non-strings." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1095", {}, {}, true); } stackIdx--; theStack[stackIdx].s.append(theStack[stackIdx+1].s); @@ -803,14 +797,12 @@ RTXProcessor::applyRule(const UString& rule) { if(theStack[stackIdx].mode != 2 && theStack[stackIdx].mode != 3) { - cerr << "Cannot append non-string to chunk surface." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1096", {}, {}, true); } stackIdx--; if(theStack[stackIdx].mode != 3) { - cerr << "Cannot APPENDSURFACE to non-chunk." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1097", {"action"}, {"APPENDSURFACE"}, true); } if(theStack[stackIdx+1].mode == 2) { @@ -831,14 +823,12 @@ RTXProcessor::applyRule(const UString& rule) { if(theStack[stackIdx].mode != 2 && theStack[stackIdx].mode != 3) { - cerr << "Cannot append non-string to chunk surface." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1096", {}, {}, true); } stackIdx--; if(theStack[stackIdx].mode != 3) { - cerr << "Cannot APPENDSURFACESL to non-chunk." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1097", {"action"}, {"APPENDSURFACESL"}, true); } if(theStack[stackIdx+1].mode == 2) { @@ -859,14 +849,12 @@ RTXProcessor::applyRule(const UString& rule) { if(theStack[stackIdx].mode != 2 && theStack[stackIdx].mode != 3) { - cerr << "Cannot append non-string to chunk surface." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1096", {}, {}, true); } stackIdx--; if(theStack[stackIdx].mode != 3) { - cerr << "Cannot APPENDSURFACEREF to non-chunk." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1097", {"action"}, {"APPENDSURFACESL"}, true); } if(theStack[stackIdx+1].mode == 2) { @@ -932,8 +920,7 @@ RTXProcessor::applyRule(const UString& rule) { if(theStack[stackIdx].mode != 2) { - cerr << "Cannot DISTAG non-string." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1099", {}, {}, true); } UString& s = theStack[stackIdx].s; if(s.size() > 0 && s[0] == '<' && s[s.size()-1] == '>') @@ -958,10 +945,7 @@ RTXProcessor::applyRule(const UString& rule) { if(stackIdx == 0 || theStack[stackIdx].mode != 3) { - cerr << "Empty stack or top item is not chunk." << endl; - cerr << "Check for conditionals that might not generate output" << endl; - cerr << "and ensure that lists of attributes are complete." << endl; - exit(1); + I18n(APRC_I18N_DATA, "aprc").error("APRC1100", {}, {}, true); } theStack[stackIdx].c->rule = rl; } @@ -976,8 +960,7 @@ RTXProcessor::applyRule(const UString& rule) pushStack(StringUtils::itoa((currentInput.size() + 1) / 2)); break; default: - cerr << "unknown instruction: " << rule[i] << endl; - exit(1); + I18n(APRC_I18N_DATA, "aprc").error("APRC1101", {"rule"}, {icu::UnicodeString(rule[i])}, true); } } return true; @@ -1057,8 +1040,7 @@ RTXProcessor::readToken() } else { - cerr << "Parse Error: Wordbound blank should be immediately followed by a Lexical Unit -> [[..]]^..$" << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1102", {}, {}, true); } } else diff --git a/src/trx_compiler.cc b/src/trx_compiler.cc index 8b01907..c2d8950 100644 --- a/src/trx_compiler.cc +++ b/src/trx_compiler.cc @@ -10,6 +10,7 @@ #include #include #include +#include using namespace std; @@ -48,6 +49,14 @@ TRXCompiler::die(xmlNode* node, const char* fmt, ...) u_fputc('\n', out); exit(EXIT_FAILURE); } +void +TRXCompiler::die(xmlNode* node, icu::UnicodeString message) +{ + cerr << I18n(APRC_I18N_DATA, "aprc").format("in_file_on_line", {"file", "line"}, + {(char*)curDoc->URL, node->line}) << endl; + cerr << message << endl; + exit(EXIT_FAILURE); +} void TRXCompiler::warn(xmlNode* node, const char* fmt, ...) @@ -62,14 +71,21 @@ TRXCompiler::warn(xmlNode* node, const char* fmt, ...) u_fputc('\n', out); } +void +TRXCompiler::warn(xmlNode* node, icu::UnicodeString message) +{ + cerr << I18n(APRC_I18N_DATA, "aprc").format("in_file_on_line", + {"file", "line"}, {(char*)curDoc->URL, node->line}) << endl; + cerr << message << endl; +} + void TRXCompiler::compile(string file) { curDoc = xmlReadFile(file.c_str(), NULL, 0); if(curDoc == NULL) { - cerr << "Error: Could not parse file '" << file << "'." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1002", {"file"}, {file.c_str()}, true); } processFile(xmlDocGetRootElement(curDoc)); } @@ -102,7 +118,7 @@ TRXCompiler::requireAttr(xmlNode* node, const char* attr) return to_ustring((const char*) a->children->content); } } - die(node, "Expected attribute '%S'", to_ustring(attr).c_str()); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1103", {"attr"}, {attr})); return ""_u; // since die() exits, this will not be returned // but we each do our part to keep the typechecker happy... } @@ -127,7 +143,7 @@ TRXCompiler::getPos(xmlNode* node, bool isBlank = false) } else { - die(node, "Cannot interpret empty pos attribute."); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1104")); } } for(unsigned int i = 0; i < v.size(); i++) @@ -136,10 +152,10 @@ TRXCompiler::getPos(xmlNode* node, bool isBlank = false) { if(isBlank) { - warn(node, "Disregarding non-integer position."); + warn(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1138")); return 0; } - die(node, "Position must be an integer."); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1105")); } } int ret = StringUtils::stoi(v); @@ -156,10 +172,10 @@ TRXCompiler::getPos(xmlNode* node, bool isBlank = false) { if(isBlank) { - warn(node, "Disregarding out-of-bounds position."); + warn(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1139")); return 0; } - die(node, "Position %d is out of bounds.", ret); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1106", {"pos"}, {ret})); } if(macroPosShift.size() > 0) { @@ -173,14 +189,15 @@ TRXCompiler::processCats(xmlNode* node) { for (auto cat : children(node)) { if (!nameIs(cat, "def-cat")) { - warn(cat, "Unexpected tag in section-def-cats - ignoring"); + warn(cat, I18n(APRC_I18N_DATA, "aprc").format("APRC1140", {"node"}, {"section-def-cats"})); continue; } UString pat_name = requireAttr(cat, "n"); vector pat; for (auto item : children(cat)) { if (!nameIs(item, "cat-item")) { - warn(cat, "Unexpected tag <%S> in def-cat - ignoring", name(item).c_str()); + warn(cat, I18n(APRC_I18N_DATA, "aprc").format("APRC1141", {"node"}, + {icu::UnicodeString(name(item).data())})); continue; } PatternElement* cur = new PatternElement; @@ -191,7 +208,8 @@ TRXCompiler::processCats(xmlNode* node) pat.push_back(cur); } if(patterns.find(pat_name) != patterns.end()) { - warn(cat, "Redefinition of pattern '%S', using later value", pat_name.c_str()); + warn(cat, I18n(APRC_I18N_DATA, "aprc").format("APRC1142", {"pattern"}, + {icu::UnicodeString(pat_name.data())})); } patterns[pat_name] = pat; } @@ -202,21 +220,22 @@ TRXCompiler::processAttrs(xmlNode* node) { for (auto cat : children(node)) { if (!nameIs(cat, "def-attr")) { - warn(cat, "Unexpected tag in section-def-attrs - ignoring"); + warn(cat, I18n(APRC_I18N_DATA, "aprc").format("APRC1140", {"node"}, {"section-def-attrs"})); continue; } UString name = getattr(cat, "n"); set ats; for (auto item : children(cat)) { if (!nameIs(item, "attr-item")) { - warn(item, "Unexpected tag in def-attr - ignoring"); + warn(item, I18n(APRC_I18N_DATA, "aprc").format("APRC1140", {"node"}, {"def-attr"})); continue; } ats.insert(getattr(item, "tags")); } if(PB.isAttrDefined(name)) { - warn(cat, "Redefinition of attribute '%S' - using later definition", name.c_str()); + warn(cat, I18n(APRC_I18N_DATA, "aprc").format("APRC1143", {"attr"}, + {icu::UnicodeString(name.data())})); } PB.addAttr(name, ats); } @@ -227,7 +246,7 @@ TRXCompiler::processVars(xmlNode* node) { for (auto var : children(node)) { if (!nameIs(var, "def-var")) { - warn(var, "Unexpected tag in section-def-vars - ignoring"); + warn(var, I18n(APRC_I18N_DATA, "aprc").format("APRC1140", {"node"}, {"section-def-vars"})); continue; } UString name = requireAttr(var, "n"); @@ -241,21 +260,22 @@ TRXCompiler::processLists(xmlNode* node) { for (auto cat : children(node)) { if (!nameIs(cat, "def-list")) { - warn(cat, "Unexpected tag in section-def-lists - ignoring"); + warn(cat, I18n(APRC_I18N_DATA, "aprc").format("APRC1140", {"node"}, {"section-def-lists"})); continue; } UString name = getattr(cat, "n"); set ats; for (auto item : children(cat)) { if (!nameIs(item, "list-item")) { - warn(item, "Unexpected tag in def-list - ignoring"); + warn(item, I18n(APRC_I18N_DATA, "aprc").format("APRC1140", {"node"}, {"def-list"})); continue; } ats.insert(getattr(item, "v")); } if(lists.find(name) != lists.end()) { - warn(cat, "Redefinition of list '%S' - using later definition", name.c_str()); + warn(cat, I18n(APRC_I18N_DATA, "aprc").format("APRC1144", {"list"}, + {icu::UnicodeString(name.data())})); } lists[name] = ats; PB.addList(name, ats); @@ -267,14 +287,15 @@ TRXCompiler::gatherMacros(xmlNode* node) { for (auto mac : children(node)) { if (!nameIs(mac, "def-macro")) { - warn(mac, "Unexpected tag in section-def-macros - ignoring"); + warn(mac, I18n(APRC_I18N_DATA, "aprc").format("APRC1140", {"node"}, {"section-def-macros"})); continue; } UString name = requireAttr(mac, "n"); int npar = StringUtils::stoi(requireAttr(mac, "npar")); if(macros.find(name) != macros.end()) { - warn(mac, "Redefinition of macro '%S' - using later definition", name.c_str()); + warn(mac, I18n(APRC_I18N_DATA, "aprc").format("APRC1145", {"macro"}, + {icu::UnicodeString(name.data())})); } macros[name] = make_pair(npar, mac); } @@ -286,7 +307,8 @@ TRXCompiler::processRules(xmlNode* node) for (auto rule : children(node)) { if(xmlStrcmp(rule->name, (const xmlChar*) "rule")) { - warn(rule, "Ignoring non- element in ."); + warn(rule, I18n(APRC_I18N_DATA, "aprc").format("APRC1146", {"element", "node"}, + {"", ""})); continue; } if (getattr(rule, "i") == "yes"_u) { @@ -317,20 +339,22 @@ TRXCompiler::processRules(xmlNode* node) { if(pat) { - die(rule, "Rule cannot have multiple s."); + die(rule, I18n(APRC_I18N_DATA, "aprc").format("APRC1107")); } pat = true; vector> pls; for (auto pi : children(part)) { if (!nameIs(pi, "pattern-item")) { - warn(pi, "Ignoring non- in ."); + warn(pi, I18n(APRC_I18N_DATA, "aprc").format("APRC1146", {"element", "node"}, + {"", ""})); continue; } curPatternSize++; UString name = requireAttr(pi, "n"); if(patterns.find(name) == patterns.end()) { - die(pi, "Unknown pattern '%S'.", name.c_str()); + die(pi, I18n(APRC_I18N_DATA, "aprc").format("APRC1108", {"pattern"}, + {icu::UnicodeString(name.data())})); } else { @@ -339,7 +363,7 @@ TRXCompiler::processRules(xmlNode* node) } if(curPatternSize == 0) { - die(rule, "Rule cannot have empty pattern."); + die(rule, I18n(APRC_I18N_DATA, "aprc").format("APRC1109")); } if(curPatternSize > longestPattern) { @@ -367,7 +391,7 @@ TRXCompiler::processRules(xmlNode* node) { if(action != NULL) { - die(rule, "Rule cannot have multiple s."); + die(rule, I18n(APRC_I18N_DATA, "aprc").format("APRC1110")); } action = part; } @@ -375,7 +399,7 @@ TRXCompiler::processRules(xmlNode* node) { if(outputAction.size() > 0) { - die(part, "Rule cannot have multiple s."); + die(part, I18n(APRC_I18N_DATA, "aprc").format("APRC1111")); } inOutput = true; for (auto state : children(part)) { @@ -384,16 +408,17 @@ TRXCompiler::processRules(xmlNode* node) } else { - warn(part, "Unknown element <%S> in , ignoring.", name(part).c_str()); + warn(part, I18n(APRC_I18N_DATA, "aprc").format("APRC1147", {"node"}, + {icu::UnicodeString(name(part).data())})); } } if(!pat) { - die(rule, "Rule must have ."); + die(rule, I18n(APRC_I18N_DATA, "aprc").format("APRC1112")); } if(action == NULL) { - die(rule, "Rule must have ."); + die(rule, I18n(APRC_I18N_DATA, "aprc").format("APRC1113")); } else { @@ -445,19 +470,22 @@ TRXCompiler::processStatement(xmlNode* node) val = processValue(n); } else { - die(node, "<%S> cannot have more than two children.", name(node).c_str()); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1114", {"node"}, + {icu::UnicodeString(name(node).data())})); } } if(val.size() == 0) { - die(node, "<%S> must have two children.", name(node).c_str()); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1115", {"node"}, + {icu::UnicodeString(name(node).data())})); } if(nameIs(var, "var")) { UString vname = requireAttr(var, "n"); if(vars.find(vname) == vars.end()) { - die(var, "Undefined variable '%S'.", vname.c_str()); + die(var, I18n(APRC_I18N_DATA, "aprc").format("APRC1116", {"var"}, + {icu::UnicodeString(vname.data())})); } if(nameIs(node, "modify-case")) { @@ -482,12 +510,14 @@ TRXCompiler::processStatement(xmlNode* node) UString side = getattr(var, "side"); if(!(side.empty() || side == "tl"_u)) { - warn(var, "Cannot set side '%S', setting 'tl' instead.", side.c_str()); + warn(var, I18n(APRC_I18N_DATA, "aprc").format("APRC1148", {"side"}, + {icu::UnicodeString(side.data())})); } UString part = requireAttr(var, "part"); if(!PB.isAttrDefined(part)) { - die(var, "Unknown attribute '%S'", part.c_str()); + die(var, I18n(APRC_I18N_DATA, "aprc").format("APRC1117", {"attr"}, + {icu::UnicodeString(part.data())})); } UString set_str; set_str += PB.BCstring(part); @@ -526,7 +556,7 @@ TRXCompiler::processStatement(xmlNode* node) } else { - die(node, "Cannot set value of <%S>.", name(var).c_str()); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1118", {"node"}, {icu::UnicodeString(name(var).data())})); } } else if(nameIs(node, "out")) @@ -546,24 +576,30 @@ TRXCompiler::processStatement(xmlNode* node) UString name = requireAttr(node, "n"); if(macros.find(name) == macros.end()) { - die(node, "Unknown macro '%S'.", name.c_str()); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1119", + {"macro"}, {icu::UnicodeString(name.data())})); } vector temp; for (auto param : children(node)) { if (nameIs(param, "with-param")) { temp.push_back(getPos(param)); } else { - warn(param, "Ignoring non- in "); + warn(param, I18n(APRC_I18N_DATA, "aprc").format("APRC1146", {"element", "node"}, + {"", ""})); } } unsigned int shouldbe = macros[name].first; if(shouldbe < temp.size()) { - die(node, "Too many parameters, macro '%S' expects %d, got %d.", name.c_str(), shouldbe, temp.size()); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1120", {"macro", "expected", "given"}, + {icu::UnicodeString(name.data()), + to_string(shouldbe).c_str(), to_string(temp.size()).c_str()})); } if(shouldbe > temp.size()) { - die(node, "Not enough parameters, macro '%S' expects %d, got %d.", name.c_str(), shouldbe, temp.size()); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1121", {"macro", "expected", "given"}, + {icu::UnicodeString(name.data()), + to_string(shouldbe).c_str(), to_string(temp.size()).c_str()})); } macroPosShift.push_back(temp); xmlNode* mac = macros[name].second; @@ -578,7 +614,8 @@ TRXCompiler::processStatement(xmlNode* node) UString name = requireAttr(node, "n"); if(vars.find(name) == vars.end() && localVars.find(name) == localVars.end()) { - die(node, "Unknown variable '%S'.", name.c_str()); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1122", {"var"}, + {icu::UnicodeString(name.data())})); } ret += STRING; ret += (UChar)name.size(); @@ -599,7 +636,8 @@ TRXCompiler::processStatement(xmlNode* node) } else { - die(node, "Unrecognized statement '%S'", name(node).c_str()); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1123", {"statement"}, + {icu::UnicodeString(name(node).data())})); } return ret; } @@ -623,7 +661,8 @@ TRXCompiler::processValue(xmlNode* node) UString part = requireAttr(node, "part"); if(!PB.isAttrDefined(part)) { - die(node, "Unknown attribute '%S'", part.c_str()); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1117", {"attr"}, + {icu::UnicodeString(part.data())})); } ret += (UChar)part.size(); ret += part; @@ -642,7 +681,8 @@ TRXCompiler::processValue(xmlNode* node) } else { - warn(node, "Unknown clip side '%S', defaulting to 'tl'.", side.c_str()); + warn(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1149", {"side"}, + {icu::UnicodeString(side.data())})); ret += TARGETCLIP; } UString link = getattr(node, "link-to"); @@ -688,7 +728,8 @@ TRXCompiler::processValue(xmlNode* node) UString v = requireAttr(node, "n"); if(vars.find(v) == vars.end() && localVars.find(v) == localVars.end()) { - die(node, "Unknown variable '%S'.", v.c_str()); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1122", {"var"}, + {icu::UnicodeString(v.data())})); } ret += (UChar)v.size(); ret += v; @@ -700,12 +741,12 @@ TRXCompiler::processValue(xmlNode* node) if (ret.empty()) { ret.append(processValue(c)); } else { - die(node, " cannot have multiple children."); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1124")); } } if(ret.size() == 0) { - die(node, " cannot be empty."); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1125")); } ret += INT; ret += (UChar)getPos(node); @@ -740,7 +781,8 @@ TRXCompiler::processValue(xmlNode* node) } else { - warn(node, "Unknown side '%S', defaulting to target.", side.c_str()); + warn(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1150", {"side"}, + {icu::UnicodeString(side.data())})); ret += TARGETCLIP; } ret += GETCASE; @@ -780,7 +822,7 @@ TRXCompiler::processValue(xmlNode* node) ret += CHUNK; for (auto lu : children(node)) { if (!nameIs(lu, "lu")) { - die(node, " can only contain s."); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1126")); } if(ret.size() > 1) { @@ -839,7 +881,8 @@ TRXCompiler::processValue(xmlNode* node) } else { - die(node, "Unrecognized expression '%S'", name(node).c_str()); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1127", {"exp"}, + {icu::UnicodeString(name(node).data())})); } return ret; } @@ -875,7 +918,7 @@ TRXCompiler::processCond(xmlNode* node) for (auto op : children(node)) { if(ret.size() > 0) { - die(node, " cannot have multiple children"); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1128")); } else { @@ -893,7 +936,7 @@ TRXCompiler::processCond(xmlNode* node) } if(i != 2) { - die(node, " must have exactly two children"); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1115", {"node"}, {""})); } if(getattr(node, "caseless") == "yes"_u) { @@ -913,7 +956,7 @@ TRXCompiler::processCond(xmlNode* node) } if(i != 2) { - die(node, " must have exactly two children"); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1115", {"node"}, {""})); } if(getattr(node, "caseless") == "yes"_u) { @@ -934,18 +977,20 @@ TRXCompiler::processCond(xmlNode* node) } else if(list) { - die(node, " cannot have more than two children."); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1130", {"node"}, {""})); } else if(xmlStrcmp(op->name, (const xmlChar*) "list")) { - die(op, "Expected , found <%S> instead.", to_ustring((const char*)op->name).c_str()); + die(op, I18n(APRC_I18N_DATA, "aprc").format("APRC1131", {"node"}, + {icu::UnicodeString(to_ustring((const char*)op->name).data())})); } else { UString name = requireAttr(op, "n"); if(lists.find(name) == lists.end()) { - die(op, "Unknown list '%S'.", name.c_str()); + die(op, I18n(APRC_I18N_DATA, "aprc").format("APRC1132", {"list"}, + {icu::UnicodeString(name.data())})); } ret += STRING; ret += (UChar)name.size(); @@ -955,7 +1000,7 @@ TRXCompiler::processCond(xmlNode* node) } if(!list) { - die(node, " must have two children."); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1115", {"node"}, {""})); } if(getattr(node, "caseless") == "yes"_u) { @@ -975,7 +1020,7 @@ TRXCompiler::processCond(xmlNode* node) } if(i != 2) { - die(node, " must have exactly two children"); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1115", {"node"}, {""})); } if(getattr(node, "caseless") == "yes"_u) { @@ -996,18 +1041,20 @@ TRXCompiler::processCond(xmlNode* node) } else if(list) { - die(node, " cannot have more than two children."); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1130", {"node"}, {""})); } else if(xmlStrcmp(op->name, (const xmlChar*) "list")) { - die(op, "Expected , found <%S> instead.", name(op).c_str()); + die(op, I18n(APRC_I18N_DATA, "aprc").format("APRC1131", {"node"}, + {icu::UnicodeString(name(op).data())})); } else { UString name = requireAttr(op, "n"); if(lists.find(name) == lists.end()) { - die(op, "Unknown list '%S'.", name.c_str()); + die(op, I18n(APRC_I18N_DATA, "aprc").format("APRC1132", {"list"}, + {icu::UnicodeString(name.data())})); } ret += STRING; ret += (UChar)name.size(); @@ -1017,7 +1064,7 @@ TRXCompiler::processCond(xmlNode* node) } if(!list) { - die(node, " must have two children."); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1115", {"node"}, {""})); } if(getattr(node, "caseless") == "yes"_u) { @@ -1037,7 +1084,7 @@ TRXCompiler::processCond(xmlNode* node) } if(i != 2) { - die(node, " must have exactly two children"); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1115", {"node"}, {""})); } if(getattr(node, "caseless") == "yes"_u) { @@ -1058,19 +1105,20 @@ TRXCompiler::processCond(xmlNode* node) } else if(list) { - die(node, " cannot have more than two children."); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1130", {"node"}, {""})); } else if(xmlStrcmp(op->name, (const xmlChar*) "list")) { - die(op, "Expected , found <%S> instead.", - name(op).c_str()); + die(op, I18n(APRC_I18N_DATA, "aprc").format("APRC1131", {"node"}, + {icu::UnicodeString(name(op).data())})); } else { UString name = requireAttr(op, "n"); if(lists.find(name) == lists.end()) { - die(op, "Unknown list '%S'.", name.c_str()); + die(op, I18n(APRC_I18N_DATA, "aprc").format("APRC1132", {"list"}, + {icu::UnicodeString(name.data())})); } ret += STRING; ret += (UChar)name.size(); @@ -1080,7 +1128,7 @@ TRXCompiler::processCond(xmlNode* node) } if(!list) { - die(node, " must have two children."); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1115", {"node"}, {""})); } if(getattr(node, "caseless") == "yes"_u) { @@ -1093,7 +1141,8 @@ TRXCompiler::processCond(xmlNode* node) } else { - die(node, "Unrecognized condition '%S'", name(node).c_str()); + die(node, I18n(APRC_I18N_DATA, "aprc").format("APRC1133", {"condition"}, + {icu::UnicodeString(name(node).data())})); } return ret; } @@ -1109,7 +1158,7 @@ TRXCompiler::processChoose(xmlNode* node) { if(otherwise > 0) { - warn(cl, "Clauses after will not be executed."); + warn(cl, I18n(APRC_I18N_DATA, "aprc").format("APRC1151")); continue; } when++; @@ -1119,7 +1168,7 @@ TRXCompiler::processChoose(xmlNode* node) { if(test.size() != 0) { - die(n, "Cannot have multiple s in a clause."); + die(n, I18n(APRC_I18N_DATA, "aprc").format("APRC1134")); } for (auto t : children(n)) { if(test.size() == 0) @@ -1128,19 +1177,19 @@ TRXCompiler::processChoose(xmlNode* node) } else { - die(t, " must have exactly one child."); + die(t, I18n(APRC_I18N_DATA, "aprc").format("APRC1135")); } } if(test.size() == 0) { - die(n, " cannot be empty."); + die(n, I18n(APRC_I18N_DATA, "aprc").format("APRC1136")); } } else { if(test.size() == 0) { - die(n, " clause must begin with ."); + die(n, I18n(APRC_I18N_DATA, "aprc").format("APRC1137")); } block += processStatement(n); } @@ -1152,7 +1201,7 @@ TRXCompiler::processChoose(xmlNode* node) otherwise++; if(otherwise > 1) { - warn(cl, "Multiple clauses will not be executed."); + warn(cl, I18n(APRC_I18N_DATA, "aprc").format("APRC1152")); continue; } UString block; @@ -1165,12 +1214,12 @@ TRXCompiler::processChoose(xmlNode* node) } else { - warn(cl, "Empty clause."); + warn(cl, I18n(APRC_I18N_DATA, "aprc").format("APRC1153")); } } else { - warn(cl, "Ignoring unexpected clause in ."); + warn(cl, I18n(APRC_I18N_DATA, "aprc").format("APRC1154")); } } UString ret; @@ -1206,8 +1255,7 @@ TRXCompiler::write(const char* binfile) FILE* bin = fopen(binfile, "wb"); if(bin == NULL) { - cerr << "Error: Cannot open " << binfile << " for writing." << endl; - exit(EXIT_FAILURE); + I18n(APRC_I18N_DATA, "aprc").error("APRC1002", {"file"}, {binfile}, true); } vector> inRules; for(unsigned int i = 0; i < inputRules.size(); i++) diff --git a/src/trx_compiler.h b/src/trx_compiler.h index 86cb3dc..30b9e9e 100644 --- a/src/trx_compiler.h +++ b/src/trx_compiler.h @@ -110,12 +110,14 @@ private: * @param node - xml element closest to the error */ void die(xmlNode* node, const char* fmt, ...); + void die(xmlNode* node, icu::UnicodeString message); /** * Report a non-fatal error * @param node - xml element closest to the error */ void warn(xmlNode* node, const char* fmt, ...); + void warn(xmlNode* node, icu::UnicodeString message); ////////// // PARSING UTILITIES