Separate forward and backward translation rules in separate table structs A side effect is that it makes noback and nofor affect some more rules. Making noback and nofor affect all rules is something for a later commit though.
diff --git a/liblouis/compileTranslationTable.c b/liblouis/compileTranslationTable.c index e12e6fb..4d3fbad 100644 --- a/liblouis/compileTranslationTable.c +++ b/liblouis/compileTranslationTable.c
@@ -97,7 +97,8 @@ char tableList[1]; } TranslationTableChainEntry; -static TranslationTableChainEntry *translationTableChain = NULL; +static TranslationTableChainEntry *forwardTranslationTableChain = NULL; +static TranslationTableChainEntry *backwardTranslationTableChain = NULL; typedef struct DisplayTableChainEntry { struct DisplayTableChainEntry *next; @@ -441,9 +442,16 @@ /* update references to the old table */ { TranslationTableChainEntry *entry; - for (entry = translationTableChain; entry != NULL; entry = entry->next) - if (entry->table == *table) - entry->table = (TranslationTableHeader *)newTable; + if (forwardTranslationTableChain) + for (entry = forwardTranslationTableChain; entry != NULL; + entry = entry->next) + if (entry->table == *table) + entry->table = (TranslationTableHeader *)newTable; + if (backwardTranslationTableChain) + for (entry = backwardTranslationTableChain; entry != NULL; + entry = entry->next) + if (entry->table == *table) + entry->table = (TranslationTableHeader *)newTable; } newTable->tableSize = newTableSize; *table = newTable; @@ -812,6 +820,38 @@ /* The following functions are called by addRule to handle various cases. */ static void +setForwardDefinitionRule(const FileInfo *file, TranslationTableCharacter *character, + TranslationTableOffset ruleOffset, TranslationTableRule **rule, + TranslationTableHeader **table) { + if (!character) { + character = putChar(file, (*rule)->charsdots[0], table, NULL, (*rule)->index); + // putChar may have moved table, so make sure rule is still valid + *rule = (TranslationTableRule *)&(*table)->ruleArea[ruleOffset]; + } + // set the main definition rule of this character (but don't override existing + // character definitions rules or base rules) + // adding the attributes to the character has already been done elsewhere + if (character->definitionRule) { + TranslationTableRule *prevRule = + (TranslationTableRule *)&(*table) + ->ruleArea[character->definitionRule]; + char *prevOpcodeName = strdup(_lou_findOpcodeName(prevRule->opcode)); + char *newOpcodeName = strdup(_lou_findOpcodeName((*rule)->opcode)); + _lou_logMessage(LOU_LOG_DEBUG, + "%s:%d: Character already defined (%s). The existing %s rule " + "will take precedence over the new %s rule.", + file->fileName, file->lineNumber, + printSource(file->sourceFile, prevRule->sourceFile, + prevRule->sourceLine), + prevOpcodeName, newOpcodeName); + free(prevOpcodeName); + free(newOpcodeName); + } else { + character->definitionRule = ruleOffset; + } +} + +static void addForwardRuleWithSingleChar(const FileInfo *file, TranslationTableOffset ruleOffset, TranslationTableRule **rule, TranslationTableHeader **table) { /* direction = 0, rule->charslen = 1 */ @@ -824,32 +864,9 @@ if ((*rule)->opcode == CTO_CompDots || (*rule)->opcode == CTO_Comp6) { character->compRule = ruleOffset; return; - } else { - // if the new rule is a character definition rule, set the main definition rule of - // this character to it, but don't override existing character definitions rules - // or base rules - // adding the attributes to the character has already been done elsewhere - if ((*rule)->opcode >= CTO_Space && (*rule)->opcode < CTO_UpLow) { - if (character->definitionRule) { - TranslationTableRule *prevRule = - (TranslationTableRule *)&(*table) - ->ruleArea[character->definitionRule]; - char *prevOpcodeName = strdup(_lou_findOpcodeName(prevRule->opcode)); - char *newOpcodeName = strdup(_lou_findOpcodeName((*rule)->opcode)); - _lou_logMessage(LOU_LOG_DEBUG, - "%s:%d: Character already defined (%s). The existing %s rule " - "will take precedence over the new %s rule.", - file->fileName, file->lineNumber, - printSource(file->sourceFile, prevRule->sourceFile, - prevRule->sourceLine), - prevOpcodeName, newOpcodeName); - free(prevOpcodeName); - free(newOpcodeName); - } else { - character->definitionRule = ruleOffset; - } - } - } + } else if ((*rule)->opcode >= CTO_Space && (*rule)->opcode < CTO_UpLow) + // character definition rule + setForwardDefinitionRule(file, character, ruleOffset, rule, table); // add the new rule to the list of rules associated with this character // if the new rule is a character definition rule, it is inserted at the end of the // list, otherwise it is inserted before the first character definition rule @@ -861,9 +878,9 @@ if (r->charslen == 0) break; if (r->opcode >= CTO_Space && r->opcode < CTO_UpLow) if (!((*rule)->opcode >= CTO_Space && (*rule)->opcode < CTO_UpLow)) break; - otherRule = &r->charsnext; + otherRule = &r->next; } - (*rule)->charsnext = *otherRule; + (*rule)->next = *otherRule; *otherRule = ruleOffset; } @@ -872,15 +889,15 @@ TranslationTableRule *rule, TranslationTableHeader *table) { /* direction = 0 rule->charslen > 1 */ TranslationTableOffset *forRule = - &table->forRules[_lou_stringHash(&rule->charsdots[0], 0, NULL)]; + &table->rules[_lou_stringHash(&rule->charsdots[0], 0, NULL)]; while (*forRule) { TranslationTableRule *r = (TranslationTableRule *)&table->ruleArea[*forRule]; if (rule->charslen > r->charslen) break; if (rule->charslen == r->charslen) if ((r->opcode == CTO_Always) && (rule->opcode != CTO_Always)) break; - forRule = &r->charsnext; + forRule = &r->next; } - rule->charsnext = *forRule; + rule->next = *forRule; *forRule = ruleOffset; } @@ -905,9 +922,9 @@ if ((*rule)->charslen > r->charslen || r->dotslen == 0) break; if (r->opcode >= CTO_Space && r->opcode < CTO_UpLow) if (!((*rule)->opcode >= CTO_Space && (*rule)->opcode < CTO_UpLow)) break; - otherRule = &r->dotsnext; + otherRule = &r->next; } - (*rule)->dotsnext = *otherRule; + (*rule)->next = *otherRule; *otherRule = ruleOffset; } @@ -916,7 +933,7 @@ TranslationTableOffset ruleOffset, TranslationTableRule *rule, TranslationTableHeader *table) { /* direction = 1, dotslen > 1 */ - TranslationTableOffset *backRule = &table->backRules[_lou_stringHash(cells, 0, NULL)]; + TranslationTableOffset *backRule = &table->rules[_lou_stringHash(cells, 0, NULL)]; if (rule->opcode == CTO_SwapCc) return; int ruleLength = dotslen + rule->charslen; while (*backRule) { @@ -925,132 +942,105 @@ if (ruleLength > rLength) break; if (rLength == ruleLength) if ((r->opcode == CTO_Always) && (rule->opcode != CTO_Always)) break; - backRule = &r->dotsnext; + backRule = &r->next; } - rule->dotsnext = *backRule; + rule->next = *backRule; *backRule = ruleOffset; } static int -addForwardPassRule(TranslationTableOffset ruleOffset, TranslationTableRule *rule, +addPassRule(TranslationTableOffset ruleOffset, TranslationTableRule *rule, TranslationTableHeader *table) { - TranslationTableOffset *forPassRule; + TranslationTableOffset *passRule; switch (rule->opcode) { case CTO_Correct: - forPassRule = &table->forPassRules[0]; + passRule = &table->passRules[0]; break; case CTO_Context: - forPassRule = &table->forPassRules[1]; + passRule = &table->passRules[1]; break; case CTO_Pass2: - forPassRule = &table->forPassRules[2]; + passRule = &table->passRules[2]; break; case CTO_Pass3: - forPassRule = &table->forPassRules[3]; + passRule = &table->passRules[3]; break; case CTO_Pass4: - forPassRule = &table->forPassRules[4]; + passRule = &table->passRules[4]; break; default: return 0; } - while (*forPassRule) { - TranslationTableRule *r = (TranslationTableRule *)&table->ruleArea[*forPassRule]; + while (*passRule) { + TranslationTableRule *r = (TranslationTableRule *)&table->ruleArea[*passRule]; if (rule->charslen > r->charslen) break; - forPassRule = &r->charsnext; + passRule = &r->next; } - rule->charsnext = *forPassRule; - *forPassRule = ruleOffset; + rule->next = *passRule; + *passRule = ruleOffset; return 1; } static int -addBackwardPassRule(TranslationTableOffset ruleOffset, TranslationTableRule *rule, - TranslationTableHeader *table) { - TranslationTableOffset *backPassRule; - switch (rule->opcode) { - case CTO_Correct: - backPassRule = &table->backPassRules[0]; - break; - case CTO_Context: - backPassRule = &table->backPassRules[1]; - break; - case CTO_Pass2: - backPassRule = &table->backPassRules[2]; - break; - case CTO_Pass3: - backPassRule = &table->backPassRules[3]; - break; - case CTO_Pass4: - backPassRule = &table->backPassRules[4]; - break; - default: - return 0; - } - while (*backPassRule) { - TranslationTableRule *r = (TranslationTableRule *)&table->ruleArea[*backPassRule]; - if (rule->charslen > r->charslen) break; - backPassRule = &r->dotsnext; - } - rule->dotsnext = *backPassRule; - *backPassRule = ruleOffset; - return 1; -} - -static int -addRule(const FileInfo *file, TranslationTableOpcode opcode, const CharsString *ruleChars, - const CharsString *ruleDots, TranslationTableCharacterAttributes after, - TranslationTableCharacterAttributes before, TranslationTableOffset *ruleOffset, - TranslationTableRule **rule, int noback, int nofor, +allocateRule(const FileInfo *file, const CharsString *chars, const CharsString *dots, + TranslationTableOffset *offset, TranslationTableRule **rule, TranslationTableHeader **table) { + int ruleSize = sizeof(TranslationTableRule) - (DEFAULTRULESIZE * CHARSIZE); + if (chars) ruleSize += CHARSIZE * chars->length; + if (dots) ruleSize += CHARSIZE * dots->length; + if (!allocateSpaceInTranslationTable(file, offset, ruleSize, table)) return 0; + *rule = (TranslationTableRule *)&(*table)->ruleArea[*offset]; + // populate fields + (*rule)->sourceFile = file->sourceFile; + (*rule)->sourceLine = file->lineNumber; + (*rule)->index = (*table)->ruleCounter++; + if (chars) + memcpy(&(*rule)->charsdots[0], &chars->chars[0], + CHARSIZE * ((*rule)->charslen = chars->length)); + else + (*rule)->charslen = 0; + if (dots) + memcpy(&(*rule)->charsdots[(*rule)->charslen], &dots->chars[0], + CHARSIZE * ((*rule)->dotslen = dots->length)); + else + (*rule)->dotslen = 0; + return 1; +} + + +static int +addForwardOrBackwardRule(const FileInfo *file, TranslationTableOpcode opcode, + const CharsString *ruleChars, const CharsString *ruleDots, + TranslationTableCharacterAttributes after, + TranslationTableCharacterAttributes before, TranslationTableOffset *ruleOffset, + TranslationTableRule **rule, int forward, TranslationTableHeader **table) { /* Add a rule to the table, using the hash function to find the start of * chains and chaining both the chars and dots strings */ TranslationTableOffset offset; - int ruleSize = sizeof(TranslationTableRule) - (DEFAULTRULESIZE * CHARSIZE); - if (ruleChars) ruleSize += CHARSIZE * ruleChars->length; - if (ruleDots) ruleSize += CHARSIZE * ruleDots->length; - if (!allocateSpaceInTranslationTable(file, &offset, ruleSize, table)) return 0; - TranslationTableRule *r = (TranslationTableRule *)&(*table)->ruleArea[offset]; + TranslationTableRule *r; + if (!allocateRule(file, ruleChars, ruleDots, &offset, &r, table)) return 0; if (rule) *rule = r; if (ruleOffset) *ruleOffset = offset; - r->sourceFile = file->sourceFile; - r->sourceLine = file->lineNumber; - r->index = (*table)->ruleCounter++; r->opcode = opcode; r->after = after; r->before = before; r->nocross = 0; - if (ruleChars) - memcpy(&r->charsdots[0], &ruleChars->chars[0], - CHARSIZE * (r->charslen = ruleChars->length)); - else - r->charslen = 0; - if (ruleDots) - memcpy(&r->charsdots[r->charslen], &ruleDots->chars[0], - CHARSIZE * (r->dotslen = ruleDots->length)); - else - r->dotslen = 0; /* link new rule into table. */ if (opcode == CTO_SwapCc || opcode == CTO_SwapCd || opcode == CTO_SwapDd) return 1; if (opcode >= CTO_Context && opcode <= CTO_Pass4) if (!(opcode == CTO_Context && r->charslen > 0)) { - if (!nofor) - if (!addForwardPassRule(offset, r, *table)) return 0; - if (!noback) - if (!addBackwardPassRule(offset, r, *table)) return 0; + if (!addPassRule(offset, r, *table)) return 0; return 1; } - if (!nofor) { + if (forward) { if (r->charslen == 1) addForwardRuleWithSingleChar(file, offset, &r, table); else if (r->charslen > 1) addForwardRuleWithMultipleChars(offset, r, *table); - } - if (!noback) { + } else { widechar *cells; int dotslen; - if (r->opcode == CTO_Context) { cells = &r->charsdots[0]; dotslen = r->charslen; @@ -1062,6 +1052,50 @@ addBackwardRuleWithSingleCell(file, *cells, offset, &r, table); } else if (dotslen > 1) addBackwardRuleWithMultipleCells(cells, dotslen, offset, r, *table); + if (r->opcode >= CTO_Space && r->opcode < CTO_UpLow && r->charslen == 1) + // set definitionRule, which the `attribute' opcode needs to set attributes + // on associated dots + setForwardDefinitionRule(file, NULL, offset, &r, table); + } + return 1; +} + +static int +addForwardRule(const FileInfo *file, TranslationTableOpcode opcode, + const CharsString *ruleChars, const CharsString *ruleDots, + TranslationTableCharacterAttributes after, + TranslationTableCharacterAttributes before, TranslationTableOffset *ruleOffset, + TranslationTableRule **rule, TranslationTableHeader **table) { + return addForwardOrBackwardRule( + file, opcode, ruleChars, ruleDots, after, before, ruleOffset, rule, 1, table); +} + +static int +addBackwardRule(const FileInfo *file, TranslationTableOpcode opcode, + const CharsString *ruleChars, const CharsString *ruleDots, + TranslationTableCharacterAttributes after, + TranslationTableCharacterAttributes before, TranslationTableOffset *ruleOffset, + TranslationTableRule **rule, TranslationTableHeader **table) { + return addForwardOrBackwardRule( + file, opcode, ruleChars, ruleDots, after, before, ruleOffset, rule, 0, table); +} + +static int +addRule(const FileInfo *file, TranslationTableOpcode opcode, const CharsString *ruleChars, + const CharsString *ruleDots, TranslationTableCharacterAttributes forwardAfter, + TranslationTableCharacterAttributes backwardAfter, + TranslationTableCharacterAttributes forwardBefore, + TranslationTableCharacterAttributes backwardBefore, int noback, int nofor, + TranslationTableHeader **forwardTable, TranslationTableHeader **backwardTable) { + if (forwardTable && !nofor) { + if (!addForwardRule(file, opcode, ruleChars, ruleDots, forwardAfter, + forwardBefore, NULL, NULL, forwardTable)) + return 0; + } + if (backwardTable && !noback) { + if (!addBackwardRule(file, opcode, ruleChars, ruleDots, backwardAfter, + backwardBefore, NULL, NULL, backwardTable)) + return 0; } return 1; } @@ -1573,7 +1607,8 @@ static int includeFile(const FileInfo *file, CharsString *includedFile, - TranslationTableHeader **table, DisplayTableHeader **displayTable); + TranslationTableHeader **forwardTable, TranslationTableHeader **backwardTable, + DisplayTableHeader **displayTable); static TranslationTableOffset findRuleName(const CharsString *name, const TranslationTableHeader *table) { @@ -1650,7 +1685,7 @@ static int compileSwap(FileInfo *file, TranslationTableOpcode opcode, int noback, int nofor, - TranslationTableHeader **table) { + TranslationTableHeader **forwardTable, TranslationTableHeader **backwardTable) { CharsString ruleChars; CharsString ruleDots; CharsString name; @@ -1670,10 +1705,18 @@ } else { if (!compileSwapDots(file, &replacements, &ruleDots)) return 0; } - if (!addRule(file, opcode, &ruleChars, &ruleDots, 0, 0, &ruleOffset, NULL, noback, - nofor, table)) - return 0; - if (!addRuleName(file, &name, ruleOffset, *table)) return 0; + if (forwardTable && !nofor) { + if (!addForwardRule(file, opcode, &ruleChars, &ruleDots, 0, 0, &ruleOffset, NULL, + forwardTable)) + return 0; + if (!addRuleName(file, &name, ruleOffset, *forwardTable)) return 0; + } + if (backwardTable && !noback) { + if (!addBackwardRule(file, opcode, &ruleChars, &ruleDots, 0, 0, &ruleOffset, NULL, + backwardTable)) + return 0; + if (!addRuleName(file, &name, ruleOffset, *backwardTable)) return 0; + } return 1; } @@ -1828,20 +1871,20 @@ } static inline int -wantsString(TranslationTableOpcode opcode, int actionPart, int nofor) { +wantsString(TranslationTableOpcode opcode, int actionPart, int backward) { if (opcode == CTO_Correct) return 1; if (opcode != CTO_Context) return 0; - return !nofor == !actionPart; + return !backward == !actionPart; } static int verifyStringOrDots(const FileInfo *file, TranslationTableOpcode opcode, int isString, - int actionPart, int nofor) { - if (!wantsString(opcode, actionPart, nofor) == !isString) return 1; + int actionPart, int backward) { + if (!wantsString(opcode, actionPart, backward) == !isString) return 1; compileError(file, "%s are not allowed in the %s part of a %s translation %s rule.", isString ? "strings" : "dots", getPartName(actionPart), - nofor ? "backward" : "forward", _lou_findOpcodeName(opcode)); + backward ? "backward" : "forward", _lou_findOpcodeName(opcode)); return 0; } @@ -1858,8 +1901,8 @@ } static int -compilePassOpcode(const FileInfo *file, TranslationTableOpcode opcode, int noback, - int nofor, TranslationTableHeader **table) { +compilePassOpcode(const FileInfo *file, TranslationTableOpcode opcode, int forward, + TranslationTableHeader **table) { static CharsString passRuleChars; static CharsString passRuleDots; /* Compile the operands of a pass opcode */ @@ -1929,7 +1972,7 @@ passLinepos++; break; case pass_string: - if (!verifyStringOrDots(file, opcode, 1, 0, nofor)) { + if (!verifyStringOrDots(file, opcode, 1, 0, !forward)) { return 0; } passLinepos++; @@ -1942,7 +1985,7 @@ } goto testDoCharsDots; case pass_dots: - if (!verifyStringOrDots(file, opcode, 0, 0, nofor)) { + if (!verifyStringOrDots(file, opcode, 0, 0, !forward)) { return 0; } passLinepos++; @@ -2166,7 +2209,7 @@ } switch ((passSubOp = passLine.chars[passLinepos])) { case pass_string: - if (!verifyStringOrDots(file, opcode, 1, 1, nofor)) { + if (!verifyStringOrDots(file, opcode, 1, 1, !forward)) { return 0; } passLinepos++; @@ -2175,7 +2218,7 @@ passGetString(&passLine, &passLinepos, &passHoldString, file); goto actionDoCharsDots; case pass_dots: - if (!verifyStringOrDots(file, opcode, 0, 1, nofor)) { + if (!verifyStringOrDots(file, opcode, 0, 1, !forward)) { return 0; } passLinepos++; @@ -2306,19 +2349,17 @@ { widechar *characters; int length; - int found = passFindCharacters( - file, passInstructions, passRuleDots.length, &characters, &length); - - if (!found) return 0; - + if (!passFindCharacters( + file, passInstructions, passRuleDots.length, &characters, &length)) + return 0; if (characters) { for (k = 0; k < length; k += 1) passRuleChars.chars[k] = characters[k]; passRuleChars.length = k; } } - if (!addRule(file, opcode, &passRuleChars, &passRuleDots, 0, 0, NULL, NULL, noback, - nofor, table)) + if (!addForwardOrBackwardRule(file, opcode, &passRuleChars, &passRuleDots, 0, 0, NULL, + NULL, forward, table)) return 0; return 1; } @@ -2327,14 +2368,13 @@ static int compileBrailleIndicator(FileInfo *file, const char *ermsg, TranslationTableOpcode opcode, - TranslationTableOffset *ruleOffset, int noback, int nofor, - TranslationTableHeader **table) { + TranslationTableOffset *ruleOffset, int forward, TranslationTableHeader **table) { CharsString token; CharsString cells; if (!getToken(file, &token, ermsg)) return 0; if (!parseDots(file, &cells, &token)) return 0; - return addRule( - file, opcode, NULL, &cells, 0, 0, ruleOffset, NULL, noback, nofor, table); + return addForwardOrBackwardRule( + file, opcode, NULL, &cells, 0, 0, ruleOffset, NULL, forward, table); } static int @@ -2351,7 +2391,7 @@ } static int -compileGrouping(FileInfo *file, int noback, int nofor, TranslationTableHeader **table, +compileGrouping(FileInfo *file, int forward, TranslationTableHeader **table, DisplayTableHeader **displayTable) { int k; CharsString name; @@ -2387,8 +2427,8 @@ charsDotsPtr->attributes |= CTC_Math; charsDotsPtr = putDots(file, dotsParsed.chars[1], table, (*table)->ruleCounter); charsDotsPtr->attributes |= CTC_Math; - if (!addRule(file, CTO_Grouping, &groupChars, &dotsParsed, 0, 0, &ruleOffset, - NULL, noback, nofor, table)) + if (!addForwardOrBackwardRule(file, CTO_Grouping, &groupChars, &dotsParsed, 0, 0, + &ruleOffset, NULL, forward, table)) return 0; if (!addRuleName(file, &name, ruleOffset, *table)) return 0; } @@ -2402,18 +2442,656 @@ endChar = groupChars.chars[1]; endDots = dotsParsed.chars[1]; groupChars.length = dotsParsed.length = 1; - if (!addRule(file, CTO_Math, &groupChars, &dotsParsed, 0, 0, NULL, NULL, noback, - nofor, table)) + if (!addForwardOrBackwardRule(file, CTO_Math, &groupChars, &dotsParsed, 0, 0, + NULL, NULL, forward, table)) return 0; groupChars.chars[0] = endChar; dotsParsed.chars[0] = endDots; - if (!addRule(file, CTO_Math, &groupChars, &dotsParsed, 0, 0, NULL, NULL, noback, - nofor, table)) + if (!addForwardOrBackwardRule(file, CTO_Math, &groupChars, &dotsParsed, 0, 0, + NULL, NULL, forward, table)) return 0; } return 1; } +static int +compileBeforeAfter(FileInfo *file) { + /* 1=before, 2=after, 0=error */ + CharsString token; + CharsString tmp; + if (!getToken(file, &token, "last word before or after")) return 0; + if (!parseChars(file, &tmp, &token)) return 0; + if (eqasc2uni((unsigned char *)"before", tmp.chars, 6)) + return 1; + else if (eqasc2uni((unsigned char *)"after", tmp.chars, 5)) + return 2; + return 0; +} + +static int +compileModeIndicator(FileInfo *file, TranslationTableOpcode opcode, int forward, + TranslationTableHeader **table) { + CharsString token; + TranslationTableCharacterAttributes mode; + int i; + switch (opcode) { + case CTO_CapsLetter: + case CTO_BegCapsWord: + case CTO_EndCapsWord: + case CTO_BegCaps: + case CTO_EndCaps: + case CTO_BegCapsPhrase: + case CTO_EndCapsPhrase: + case CTO_LenCapsPhrase: + mode = CTC_UpperCase; + i = 0; + opcode += (CTO_ModeLetter - CTO_CapsLetter); + break; + default: + if (!getToken(file, &token, "attribute name")) return 0; + if (!(*table)->characterClasses && !allocateCharacterClasses(*table)) { + return 0; + } + const CharacterClass *characterClass = findCharacterClass(&token, *table); + if (!characterClass) { + characterClass = + addCharacterClass(file, token.chars, token.length, *table, 1); + if (!characterClass) return 0; + } + mode = characterClass->attribute; + if (!(mode == CTC_UpperCase || mode == CTC_Digit) && mode >= CTC_Space && + mode <= CTC_LitDigit) { + compileError(file, + "mode must be \"uppercase\", \"digit\", or a custom " + "attribute name."); + return 0; + } + /* check if this mode is already defined and if the number of modes does + * not exceed the maximal number */ + if (mode == CTC_UpperCase) + i = 0; + else { + for (i = 1; i < MAX_MODES && (*table)->modes[i].value; i++) { + if ((*table)->modes[i].mode == mode) { + break; + } + } + if (i == MAX_MODES) { + compileError(file, "Max number of modes (%i) reached", MAX_MODES); + return 0; + } + } + } + if (!(*table)->modes[i].value) + (*table)->modes[i] = (EmphasisClass){ plain_text, mode, + 0x1 << (MAX_EMPH_CLASSES + i), MAX_EMPH_CLASSES + i }; + switch (opcode) { + case CTO_BegModePhrase: { + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + if (!compileBrailleIndicator(file, "first word capital sign", + // when mode is not caps (i != 0), provide enough information + // for back-translator to be able to recognize and ignore the + // indicator (but it won't be able to determine the mode) + i == 0 ? CTO_BegCapsPhrase : CTO_BegModePhrase, &ruleOffset, forward, + table)) + return 0; + (*table)->emphRules[MAX_EMPH_CLASSES + i][begPhraseOffset] = ruleOffset; + return 1; + } + case CTO_EndModePhrase: { + TranslationTableOffset ruleOffset; + switch (compileBeforeAfter(file)) { + case 1: // before + if ((*table)->emphRules[MAX_EMPH_CLASSES + i][endPhraseAfterOffset]) { + compileError(file, "Capital sign after last word already defined."); + return 0; + } + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + if (!compileBrailleIndicator(file, "capital sign before last word", + i == 0 ? CTO_EndCapsPhraseBefore : CTO_EndModePhrase, &ruleOffset, + forward, table)) + return 0; + (*table)->emphRules[MAX_EMPH_CLASSES + i][endPhraseBeforeOffset] = ruleOffset; + return 1; + case 2: // after + if ((*table)->emphRules[MAX_EMPH_CLASSES + i][endPhraseBeforeOffset]) { + compileError(file, "Capital sign before last word already defined."); + return 0; + } + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + if (!compileBrailleIndicator(file, "capital sign after last word", + i == 0 ? CTO_EndCapsPhraseAfter : CTO_EndModePhrase, &ruleOffset, + forward, table)) + return 0; + (*table)->emphRules[MAX_EMPH_CLASSES + i][endPhraseAfterOffset] = ruleOffset; + return 1; + default: // error + compileError(file, "Invalid lastword indicator location."); + return 0; + } + return 0; + } + case CTO_BegMode: { + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + if (!compileBrailleIndicator(file, "first letter capital sign", + i == 0 ? CTO_BegCaps : CTO_BegMode, &ruleOffset, forward, table)) + return 0; + (*table)->emphRules[MAX_EMPH_CLASSES + i][begOffset] = ruleOffset; + return 1; + } + case CTO_EndMode: { + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + if (!compileBrailleIndicator(file, "last letter capital sign", + i == 0 ? CTO_EndCaps : CTO_EndMode, &ruleOffset, forward, table)) + return 0; + (*table)->emphRules[MAX_EMPH_CLASSES + i][endOffset] = ruleOffset; + return 1; + } + case CTO_ModeLetter: { + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + if (!compileBrailleIndicator(file, "single letter capital sign", + i == 0 ? CTO_CapsLetter : CTO_ModeLetter, &ruleOffset, forward, + table)) + return 0; + (*table)->emphRules[MAX_EMPH_CLASSES + i][letterOffset] = ruleOffset; + return 1; + } + case CTO_BegModeWord: { + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + if (!compileBrailleIndicator(file, "capital word", + i == 0 ? CTO_BegCapsWord : CTO_BegModeWord, &ruleOffset, forward, + table)) + return 0; + (*table)->emphRules[MAX_EMPH_CLASSES + i][begWordOffset] = ruleOffset; + return 1; + } + case CTO_EndModeWord: { + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + if (!compileBrailleIndicator(file, "capital word stop", + i == 0 ? CTO_EndCapsWord : CTO_EndModeWord, &ruleOffset, forward, + table)) + return 0; + (*table)->emphRules[MAX_EMPH_CLASSES + i][endWordOffset] = ruleOffset; + return 1; + } + case CTO_LenModePhrase: + return (*table)->emphRules[MAX_EMPH_CLASSES + i][lenPhraseOffset] = + compileNumber(file); + default: + break; + } + return 0; +} + +static int +compileEmphClass(FileInfo *file, TranslationTableHeader **table) { + CharsString emphClass; + if (!getToken(file, &emphClass, "emphasis class")) { + compileError(file, "emphclass must be followed by a valid class name."); + return 0; + } + int k, i; + char *s = malloc(sizeof(char) * (emphClass.length + 1)); + for (k = 0; k < emphClass.length; k++) s[k] = (char)emphClass.chars[k]; + s[k++] = '\0'; + for (i = 0; i < MAX_EMPH_CLASSES && (*table)->emphClassNames[i]; i++) + if (strcmp(s, (*table)->emphClassNames[i]) == 0) { + _lou_logMessage(LOU_LOG_DEBUG, "Duplicate emphasis class: %s", s); + free(s); + return 1; + } + if (i == MAX_EMPH_CLASSES) { + _lou_logMessage(LOU_LOG_ERROR, "Max number of emphasis classes (%i) reached", + MAX_EMPH_CLASSES); + errorCount++; + free(s); + return 0; + } + switch (i) { + /* For backwards compatibility (i.e. because programs will assume + * the first 3 typeform bits are `italic', `underline' and `bold') + * we require that the first 3 emphclass definitions are (in that + * order): + * + * emphclass italic + * emphclass underline + * emphclass bold + * + * While it would be possible to use the emphclass opcode only for + * defining _additional_ classes (not allowing for them to be called + * italic, underline or bold), thereby reducing the amount of + * boilerplate, we deliberately choose not to do that in order to + * not give italic, underline and bold any special status. The + * hope is that eventually all programs will use liblouis for + * emphasis the recommended way (i.e. by looking up the supported + * typeforms in the documentation or API) so that we can drop this + * restriction. + */ + case 0: + if (strcmp(s, "italic") != 0) { + _lou_logMessage(LOU_LOG_ERROR, + "First emphasis class must be \"italic\" but got " + "%s", + s); + errorCount++; + free(s); + return 0; + } + break; + case 1: + if (strcmp(s, "underline") != 0) { + _lou_logMessage(LOU_LOG_ERROR, + "Second emphasis class must be \"underline\" but " + "got " + "%s", + s); + errorCount++; + free(s); + return 0; + } + break; + case 2: + if (strcmp(s, "bold") != 0) { + _lou_logMessage(LOU_LOG_ERROR, + "Third emphasis class must be \"bold\" but got " + "%s", + s); + errorCount++; + free(s); + return 0; + } + break; + } + (*table)->emphClassNames[i] = s; + (*table)->emphClasses[i] = (EmphasisClass){ emph_1 + << i, /* relies on the order of typeforms emph_1..emph_10 */ + 0, 0x1 << i, i }; + return 1; +} + +static int +compileEmphIndicator(FileInfo *file, TranslationTableOpcode opcode, int forward, + TranslationTableHeader **table) { + CharsString token, emphClass, ruleChars; + if (!getToken(file, &token, "emphasis class")) return 0; + if (!parseChars(file, &emphClass, &token)) return 0; + char *s = malloc(sizeof(char) * (emphClass.length + 1)); + int k, i; + for (k = 0; k < emphClass.length; k++) s[k] = (char)emphClass.chars[k]; + s[k++] = '\0'; + for (i = 0; i < MAX_EMPH_CLASSES && (*table)->emphClassNames[i]; i++) + if (strcmp(s, (*table)->emphClassNames[i]) == 0) break; + if (i == MAX_EMPH_CLASSES || !(*table)->emphClassNames[i]) { + _lou_logMessage(LOU_LOG_ERROR, "Emphasis class %s not declared", s); + errorCount++; + free(s); + return 0; + } + int ok = 0; + switch (opcode) { + case CTO_EmphLetter: { + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + // provide enough information for back-translator to be able to recognize + // and ignore the indicator (but it won't be able to determine the + // emphasis class) + if (!compileBrailleIndicator( + file, "single letter", CTO_EmphLetter, &ruleOffset, forward, table)) + break; + (*table)->emphRules[i][letterOffset] = ruleOffset; + ok = 1; + break; + } + case CTO_BegEmphWord: { + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + if (!compileBrailleIndicator( + file, "word", CTO_BegEmphWord, &ruleOffset, forward, table)) + break; + (*table)->emphRules[i][begWordOffset] = ruleOffset; + ok = 1; + break; + } + case CTO_EndEmphWord: { + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + if (!compileBrailleIndicator( + file, "word stop", CTO_EndEmphWord, &ruleOffset, forward, table)) + break; + (*table)->emphRules[i][endWordOffset] = ruleOffset; + ok = 1; + break; + } + case CTO_BegEmph: { + /* fail if both begemph and any of begemphphrase or begemphword are + * defined */ + if ((*table)->emphRules[i][begWordOffset] || + (*table)->emphRules[i][begPhraseOffset]) { + compileError(file, + "Cannot define emphasis for both no context and word or " + "phrase context, i.e. cannot have both begemph and " + "begemphword or begemphphrase."); + break; + } + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + if (!compileBrailleIndicator( + file, "first letter", CTO_BegEmph, &ruleOffset, forward, table)) + break; + (*table)->emphRules[i][begOffset] = ruleOffset; + ok = 1; + break; + } + case CTO_EndEmph: { + if ((*table)->emphRules[i][endWordOffset] || + (*table)->emphRules[i][endPhraseBeforeOffset] || + (*table)->emphRules[i][endPhraseAfterOffset]) { + compileError(file, + "Cannot define emphasis for both no context and word or " + "phrase context, i.e. cannot have both endemph and " + "endemphword or endemphphrase."); + break; + } + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + if (!compileBrailleIndicator( + file, "last letter", CTO_EndEmph, &ruleOffset, forward, table)) + break; + (*table)->emphRules[i][endOffset] = ruleOffset; + ok = 1; + break; + } + case CTO_BegEmphPhrase: { + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + if (!compileBrailleIndicator( + file, "first word", CTO_BegEmphPhrase, &ruleOffset, forward, table)) + break; + (*table)->emphRules[i][begPhraseOffset] = ruleOffset; + ok = 1; + break; + } + case CTO_EndEmphPhrase: + switch (compileBeforeAfter(file)) { + case 1: { // before + if ((*table)->emphRules[i][endPhraseAfterOffset]) { + compileError(file, "last word after already defined."); + break; + } + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + if (!compileBrailleIndicator(file, "last word before", CTO_EndEmphPhrase, + &ruleOffset, forward, table)) + break; + (*table)->emphRules[i][endPhraseBeforeOffset] = ruleOffset; + ok = 1; + break; + } + case 2: { // after + if ((*table)->emphRules[i][endPhraseBeforeOffset]) { + compileError(file, "last word before already defined."); + break; + } + // not passing pointer to location inside table because + // compileBrailleIndicator may reallocate table + TranslationTableOffset ruleOffset; + if (!compileBrailleIndicator(file, "last word after", CTO_EndEmphPhrase, + &ruleOffset, forward, table)) + break; + (*table)->emphRules[i][endPhraseAfterOffset] = ruleOffset; + ok = 1; + break; + } + default: // error + compileError(file, "Invalid lastword indicator location."); + break; + } + break; + case CTO_LenEmphPhrase: + if (((*table)->emphRules[i][lenPhraseOffset] = compileNumber(file))) ok = 1; + break; + case CTO_EmphModeChars: { + if (!getRuleCharsText(file, &ruleChars)) break; + widechar *emphmodechars = (*table)->emphModeChars[i]; + int len; + for (len = 0; len < EMPHMODECHARSSIZE && emphmodechars[len]; len++) + ; + if (len + ruleChars.length > EMPHMODECHARSSIZE) { + compileError(file, "More than %d characters", EMPHMODECHARSSIZE); + break; + } + ok = 1; + for (int k = 0; k < ruleChars.length; k++) { + if (!getChar(ruleChars.chars[k], *table, NULL)) { + compileError(file, "Emphasis mode character undefined"); + ok = 0; + break; + } + emphmodechars[len++] = ruleChars.chars[k]; + } + break; + } + case CTO_NoEmphChars: { + if (!getRuleCharsText(file, &ruleChars)) break; + widechar *noemphchars = (*table)->noEmphChars[i]; + int len; + for (len = 0; len < NOEMPHCHARSSIZE && noemphchars[len]; len++) + ; + if (len + ruleChars.length > NOEMPHCHARSSIZE) { + compileError(file, "More than %d characters", NOEMPHCHARSSIZE); + break; + } + ok = 1; + for (int k = 0; k < ruleChars.length; k++) { + if (!getChar(ruleChars.chars[k], *table, NULL)) { + compileError(file, "Character undefined"); + ok = 0; + break; + } + noemphchars[len++] = ruleChars.chars[k]; + } + break; + } + default: + break; + } + free(s); + return ok; +} + +static int +compileAttribute(FileInfo *file, TranslationTableCharacterAttribute attribute, + const char *description, TranslationTableHeader **table) { + CharsString ruleChars; + if (!getRuleCharsText(file, &ruleChars)) return 0; + for (int k = 0; k < ruleChars.length; k++) { + TranslationTableCharacter *c = getChar(ruleChars.chars[k], *table, NULL); + if (!c) { + compileError(file, "% character undefined: %s", description, + _lou_showString(&ruleChars.chars[k], 1, 0)); + return 0; + } + c->attributes |= attribute; + } + return 1; +} + +static int +compileNamedAttribute( + FileInfo *file, TranslationTableOpcode opcode, TranslationTableHeader **table) { + CharsString token; + if (!getToken(file, &token, "attribute name")) { + compileError(file, "Expected %s", "attribute name"); + return 0; + } + if (!(*table)->characterClasses && !allocateCharacterClasses(*table)) { + return 0; + } + TranslationTableCharacterAttributes attribute = 0; + { + int attrNumber = -1; + switch (token.chars[0]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + attrNumber = token.chars[0] - '0'; + break; + } + if (attrNumber >= 0) { + if (opcode == CTO_Class) { + compileError(file, + "Invalid class name: may not contain digits, use " + "attribute instead of class"); + return 0; + } + if (token.length > 1 || attrNumber > 7) { + compileError(file, + "Invalid attribute name: must be a digit between 0 and 7 " + "or a word containing only letters"); + return 0; + } + if (!(*table)->numberedAttributes[attrNumber]) + // attribute not used before yet: assign it a value + (*table)->numberedAttributes[attrNumber] = + getNextNumberedAttribute(*table); + attribute = (*table)->numberedAttributes[attrNumber]; + } else { + const CharacterClass *namedAttr = findCharacterClass(&token, *table); + if (!namedAttr) { + // no class with that name: create one + namedAttr = + addCharacterClass(file, &token.chars[0], token.length, *table, 1); + if (!namedAttr) return 0; + } + // there is a class with that name or a new class was successfully + // created + attribute = namedAttr->attribute; + if (attribute == CTC_UpperCase || attribute == CTC_LowerCase) + attribute |= CTC_Letter; + } + } + CharsString characters; + if (!getCharacters(file, &characters)) return 0; + for (int i = 0; i < characters.length; i++) { + // get the character from the table, or if it is not defined yet, + // define it + TranslationTableCharacter *character = + putChar(file, characters.chars[i], table, NULL, (*table)->ruleCounter); + // set the attribute + character->attributes |= attribute; + // also set the attribute on the associated dots (if any) + if (character->basechar) + character = + (TranslationTableCharacter *)&(*table)->ruleArea[character->basechar]; + if (character->definitionRule) { + TranslationTableRule *defRule = (TranslationTableRule *)&(*table) + ->ruleArea[character->definitionRule]; + if (defRule->dotslen == 1) { + TranslationTableCharacter *dots = + getDots(defRule->charsdots[defRule->charslen], *table); + if (dots) dots->attributes |= attribute; + } + } + } + (*table)->ruleCounter++; + return 1; +} + +static int +compileBase(FileInfo *file, TranslationTableHeader **table) { + CharsString token; + if (!getToken(file, &token, "attribute name")) { + compileError(file, "base opcode must be followed by a valid attribute name."); + return 0; + } + if (!(*table)->characterClasses && !allocateCharacterClasses(*table)) { + return 0; + } + const CharacterClass *mode = findCharacterClass(&token, *table); + if (!mode) { + mode = addCharacterClass(file, token.chars, token.length, *table, 1); + if (!mode) return 0; + } + if (!(mode->attribute == CTC_UpperCase || mode->attribute == CTC_Digit) && + mode->attribute >= CTC_Space && mode->attribute <= CTC_LitDigit) { + compileError(file, + "base opcode must be followed by \"uppercase\", \"digit\", or a " + "custom attribute name."); + return 0; + } + if (!getRuleCharsText(file, &token)) return 0; + if (token.length != 1) { + compileError(file, + "Exactly one character followed by one base character is " + "required."); + return 0; + } + TranslationTableOffset characterOffset; + TranslationTableCharacter *character = + putChar(file, token.chars[0], table, &characterOffset, (*table)->ruleCounter); + if (!getRuleCharsText(file, &token)) return 0; + if (token.length != 1) { + compileError(file, "Exactly one base character is required."); + return 0; + } + TranslationTableOffset basechar; + putChar(file, token.chars[0], table, &basechar, (*table)->ruleCounter); + // putChar may have moved table, so make sure character is still valid + character = (TranslationTableCharacter *)&(*table)->ruleArea[characterOffset]; + if (character->basechar) { + if (character->basechar == basechar && character->mode == mode->attribute) { + _lou_logMessage(LOU_LOG_DEBUG, "%s:%d: Duplicate base rule.", file->fileName, + file->lineNumber); + } else { + _lou_logMessage(LOU_LOG_DEBUG, + "%s:%d: A different base rule already exists for this " + "character (%s). The existing rule will take precedence " + "over the new one.", + file->fileName, file->lineNumber, + printSource(file->sourceFile, character->sourceFile, + character->sourceLine)); + } + } else { + character->basechar = basechar; + character->mode = mode->attribute; + character->sourceFile = file->sourceFile; + character->sourceLine = file->lineNumber; + character->ruleIndex = (*table)->ruleCounter; + /* some other processing is done at the end of the compilation, in + * finalizeTable() */ + } + (*table)->ruleCounter++; + return 1; +} + /* Functions for compiling hyphenation tables */ typedef struct HyphenDict { /* hyphenation dictionary: finite state machine */ @@ -2649,7 +3327,8 @@ static int compileCharDef(FileInfo *file, TranslationTableOpcode opcode, TranslationTableCharacterAttributes attributes, int noback, int nofor, - TranslationTableHeader **table, DisplayTableHeader **displayTable) { + TranslationTableHeader **forwardTable, TranslationTableHeader **backwardTable, + DisplayTableHeader **displayTable) { CharsString ruleChars; CharsString ruleDots; if (!getRuleCharsText(file, &ruleChars)) return 0; @@ -2662,43 +3341,60 @@ compileError(file, "At least one cell is required."); return 0; } - if (table) { + if (forwardTable) { TranslationTableCharacter *character; TranslationTableCharacter *cell = NULL; int k; if (attributes & (CTC_UpperCase | CTC_LowerCase)) attributes |= CTC_Letter; - character = putChar(file, ruleChars.chars[0], table, NULL, (*table)->ruleCounter); + character = putChar(file, ruleChars.chars[0], forwardTable, NULL, + (*forwardTable)->ruleCounter); character->attributes |= attributes; for (k = ruleDots.length - 1; k >= 0; k -= 1) { - cell = getDots(ruleDots.chars[k], *table); + cell = getDots(ruleDots.chars[k], *forwardTable); if (!cell) - cell = putDots(file, ruleDots.chars[k], table, (*table)->ruleCounter); + cell = putDots(file, ruleDots.chars[k], forwardTable, + (*forwardTable)->ruleCounter); } if (ruleDots.length == 1) cell->attributes |= attributes; + if (!nofor) + if (!addForwardRule(file, opcode, &ruleChars, &ruleDots, 0, 0, NULL, NULL, + forwardTable)) + return 0; + } + if (backwardTable) { + TranslationTableCharacter *character; + TranslationTableCharacter *cell = NULL; + int k; + if (attributes & (CTC_UpperCase | CTC_LowerCase)) attributes |= CTC_Letter; + character = putChar(file, ruleChars.chars[0], backwardTable, NULL, + (*backwardTable)->ruleCounter); + character->attributes |= attributes; + for (k = ruleDots.length - 1; k >= 0; k -= 1) { + cell = getDots(ruleDots.chars[k], *backwardTable); + if (!cell) + cell = putDots(file, ruleDots.chars[k], backwardTable, + (*backwardTable)->ruleCounter); + } + if (ruleDots.length == 1) cell->attributes |= attributes; + if (!noback) { + if (!addBackwardRule(file, opcode, &ruleChars, &ruleDots, 0, 0, NULL, NULL, + backwardTable)) + return 0; + } else if (opcode >= CTO_Space && opcode < CTO_UpLow && ruleChars.length == 1) { + // set definitionRule, which the `attribute' opcode needs to set attributes + // on associated dots + TranslationTableOffset offset; + TranslationTableRule *rule; + if (!allocateRule(file, &ruleChars, &ruleDots, &offset, &rule, backwardTable)) + return 0; + setForwardDefinitionRule(file, NULL, offset, &rule, backwardTable); + } } if (displayTable && ruleDots.length == 1) putCharDotsMapping(file, ruleChars.chars[0], ruleDots.chars[0], displayTable); - if (table) - if (!addRule(file, opcode, &ruleChars, &ruleDots, 0, 0, NULL, NULL, noback, nofor, - table)) - return 0; return 1; } -static int -compileBeforeAfter(FileInfo *file) { - /* 1=before, 2=after, 0=error */ - CharsString token; - CharsString tmp; - if (!getToken(file, &token, "last word before or after")) return 0; - if (!parseChars(file, &tmp, &token)) return 0; - if (eqasc2uni((unsigned char *)"before", tmp.chars, 6)) - return 1; - else if (eqasc2uni((unsigned char *)"after", tmp.chars, 5)) - return 2; - return 0; -} - /** * Macro */ @@ -2866,27 +3562,30 @@ } static int -compileRule(FileInfo *file, TranslationTableHeader **table, - DisplayTableHeader **displayTable, const MacroList **inScopeMacros) { +compileRule(FileInfo *file, TranslationTableHeader **forwardTable, + TranslationTableHeader **backwardTable, DisplayTableHeader **displayTable, + const MacroList **inScopeMacros) { CharsString token; TranslationTableOpcode opcode; CharsString ruleChars; CharsString ruleDots; CharsString cells; CharsString scratchPad; - CharsString emphClass; - TranslationTableCharacterAttributes after = 0; - TranslationTableCharacterAttributes before = 0; + TranslationTableCharacterAttributes forwardAfter = 0; + TranslationTableCharacterAttributes backwardAfter = 0; + TranslationTableCharacterAttributes forwardBefore = 0; + TranslationTableCharacterAttributes backwardBefore = 0; int noback, nofor, nocross; noback = nofor = nocross = 0; + int lineposAfterOpcode; doOpcode: if (!getToken(file, &token, NULL)) return 1; /* blank line */ if (token.chars[0] == '#' || token.chars[0] == '<') return 1; /* comment */ if (file->lineNumber == 1 && (eqasc2uni((unsigned char *)"ISO", token.chars, 3) || eqasc2uni((unsigned char *)"UTF-8", token.chars, 5))) { - if (table) - compileHyphenation(file, &token, table); + if (forwardTable) + compileHyphenation(file, &token, forwardTable); else /* ignore the whole file */ while (_lou_getALine(file)) @@ -2894,6 +3593,7 @@ return 1; } opcode = getOpcode(file, &token); + lineposAfterOpcode = file->linepos; switch (opcode) { case CTO_Macro: { const Macro *macro; @@ -2916,7 +3616,8 @@ CharsString includedFile; if (!getToken(file, &token, "include file name")) return 0; if (!parseChars(file, &includedFile, &token)) return 0; - return includeFile(file, &includedFile, table, displayTable); + return includeFile( + file, &includedFile, forwardTable, backwardTable, displayTable); } case CTO_NoBack: if (nofor) { @@ -2933,32 +3634,42 @@ nofor = 1; goto doOpcode; case CTO_Space: - return compileCharDef( - file, opcode, CTC_Space, noback, nofor, table, displayTable); + return compileCharDef(file, opcode, CTC_Space, noback, nofor, forwardTable, + backwardTable, displayTable); case CTO_Digit: - return compileCharDef( - file, opcode, CTC_Digit, noback, nofor, table, displayTable); + return compileCharDef(file, opcode, CTC_Digit, noback, nofor, forwardTable, + backwardTable, displayTable); case CTO_LitDigit: - return compileCharDef( - file, opcode, CTC_LitDigit, noback, nofor, table, displayTable); + return compileCharDef(file, opcode, CTC_LitDigit, noback, nofor, forwardTable, + backwardTable, displayTable); case CTO_Punctuation: - return compileCharDef( - file, opcode, CTC_Punctuation, noback, nofor, table, displayTable); + return compileCharDef(file, opcode, CTC_Punctuation, noback, nofor, forwardTable, + backwardTable, displayTable); case CTO_Math: - return compileCharDef(file, opcode, CTC_Math, noback, nofor, table, displayTable); + return compileCharDef(file, opcode, CTC_Math, noback, nofor, forwardTable, + backwardTable, displayTable); case CTO_Sign: - return compileCharDef(file, opcode, CTC_Sign, noback, nofor, table, displayTable); + return compileCharDef(file, opcode, CTC_Sign, noback, nofor, forwardTable, + backwardTable, displayTable); case CTO_Letter: - return compileCharDef( - file, opcode, CTC_Letter, noback, nofor, table, displayTable); + return compileCharDef(file, opcode, CTC_Letter, noback, nofor, forwardTable, + backwardTable, displayTable); case CTO_UpperCase: - return compileCharDef( - file, opcode, CTC_UpperCase, noback, nofor, table, displayTable); + return compileCharDef(file, opcode, CTC_UpperCase, noback, nofor, forwardTable, + backwardTable, displayTable); case CTO_LowerCase: - return compileCharDef( - file, opcode, CTC_LowerCase, noback, nofor, table, displayTable); + return compileCharDef(file, opcode, CTC_LowerCase, noback, nofor, forwardTable, + backwardTable, displayTable); case CTO_Grouping: - return compileGrouping(file, noback, nofor, table, displayTable); + if (forwardTable && !nofor) { + if (!compileGrouping(file, 1, forwardTable, displayTable)) return 0; + } + if (backwardTable && !noback) { + file->linepos = lineposAfterOpcode; + if (!compileGrouping(file, 0, backwardTable, nofor ? displayTable : NULL)) + return 0; + } + return 1; case CTO_Display: if (!displayTable) return 1; // ignore if (!getRuleCharsText(file, &ruleChars)) return 0; @@ -3012,8 +3723,8 @@ while (i < next) { widechar c = m->definition[i++]; if (c == '\n') { - if (!compileRule(&tmpFile, table, displayTable, - inScopeMacros)) { + if (!compileRule(&tmpFile, forwardTable, backwardTable, + displayTable, inScopeMacros)) { _lou_logMessage(LOU_LOG_ERROR, "result of macro expansion was: %s", _lou_showString( @@ -3041,8 +3752,8 @@ ? m->substitutions[2 * subst] : m->definition_length; } else { - if (!compileRule( - &tmpFile, table, displayTable, inScopeMacros)) { + if (!compileRule(&tmpFile, forwardTable, backwardTable, + displayTable, inScopeMacros)) { _lou_logMessage(LOU_LOG_ERROR, "result of macro expansion was: %s", _lou_showString( @@ -3068,7 +3779,7 @@ /* now only opcodes follow that don't modify the display table */ default: - if (!table) return 1; + if (!(forwardTable || backwardTable)) return 1; switch (opcode) { case CTO_Locale: compileWarning(file, @@ -3079,13 +3790,22 @@ // not passing pointer to location inside table because // compileBrailleIndicator may reallocate table TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "undefined character opcode", - CTO_Undefined, &ruleOffset, noback, nofor, table)) - return 0; - (*table)->undefined = ruleOffset; + if (forwardTable && !nofor) { + if (!compileBrailleIndicator(file, "undefined character opcode", + CTO_Undefined, &ruleOffset, 1, forwardTable)) + return 0; + (*forwardTable)->undefined = ruleOffset; + } + if (backwardTable && !noback) { + file->linepos = lineposAfterOpcode; + if (!compileBrailleIndicator(file, "undefined character opcode", + CTO_Undefined, &ruleOffset, 1, backwardTable)) + return 0; + } return 1; } case CTO_Match: { + if (!forwardTable) return 1; int ok = 0; widechar *patterns = NULL; TranslationTableRule *rule; @@ -3097,38 +3817,38 @@ patterns = (widechar *)malloc(patternsByteSize); if (!patterns) _lou_outOfMemory(); memset(patterns, 0xffff, patternsByteSize); - noback = 1; getMatchPatternCharacters(file, &ptn_before); getRuleCharsText(file, &ruleChars); getMatchPatternCharacters(file, &ptn_after); getRuleDotsPattern(file, &ruleDots); - if (!addRule(file, opcode, &ruleChars, &ruleDots, after, before, &ruleOffset, - &rule, noback, nofor, table)) + if (!addForwardRule(file, opcode, &ruleChars, &ruleDots, forwardAfter, + forwardBefore, &ruleOffset, &rule, forwardTable)) goto CTO_Match_cleanup; if (ptn_before.chars[0] == '-' && ptn_before.length == 1) - len = _lou_pattern_compile( - &ptn_before.chars[0], 0, &patterns[1], 13841, *table, file); + len = _lou_pattern_compile(&ptn_before.chars[0], 0, &patterns[1], 13841, + *forwardTable, file); else len = _lou_pattern_compile(&ptn_before.chars[0], ptn_before.length, - &patterns[1], 13841, *table, file); + &patterns[1], 13841, *forwardTable, file); if (!len) goto CTO_Match_cleanup; mrk = patterns[0] = len + 1; _lou_pattern_reverse(&patterns[1]); if (ptn_after.chars[0] == '-' && ptn_after.length == 1) - len = _lou_pattern_compile( - &ptn_after.chars[0], 0, &patterns[mrk], 13841, *table, file); + len = _lou_pattern_compile(&ptn_after.chars[0], 0, &patterns[mrk], 13841, + *forwardTable, file); else len = _lou_pattern_compile(&ptn_after.chars[0], ptn_after.length, - &patterns[mrk], 13841, *table, file); + &patterns[mrk], 13841, *forwardTable, file); if (!len) goto CTO_Match_cleanup; len += mrk; if (!allocateSpaceInTranslationTable( - file, &patternsOffset, len * sizeof(widechar), table)) + file, &patternsOffset, len * sizeof(widechar), forwardTable)) goto CTO_Match_cleanup; // allocateSpaceInTranslationTable may have moved table, so make sure rule is // still valid - rule = (TranslationTableRule *)&(*table)->ruleArea[ruleOffset]; - memcpy(&(*table)->ruleArea[patternsOffset], patterns, len * sizeof(widechar)); + rule = (TranslationTableRule *)&(*forwardTable)->ruleArea[ruleOffset]; + memcpy(&(*forwardTable)->ruleArea[patternsOffset], patterns, + len * sizeof(widechar)); rule->patterns = patternsOffset; ok = 1; CTO_Match_cleanup: @@ -3137,6 +3857,7 @@ } case CTO_BackMatch: { + if (!backwardTable) return 1; int ok = 0; widechar *patterns = NULL; TranslationTableRule *rule; @@ -3148,38 +3869,38 @@ patterns = (widechar *)malloc(patternsByteSize); if (!patterns) _lou_outOfMemory(); memset(patterns, 0xffff, patternsByteSize); - nofor = 1; getMatchPatternCharacters(file, &ptn_before); getRuleCharsText(file, &ruleChars); getMatchPatternCharacters(file, &ptn_after); getRuleDotsPattern(file, &ruleDots); - if (!addRule(file, opcode, &ruleChars, &ruleDots, 0, 0, &ruleOffset, &rule, - noback, nofor, table)) + if (!addBackwardRule(file, opcode, &ruleChars, &ruleDots, 0, 0, &ruleOffset, + &rule, backwardTable)) goto CTO_BackMatch_cleanup; if (ptn_before.chars[0] == '-' && ptn_before.length == 1) - len = _lou_pattern_compile( - &ptn_before.chars[0], 0, &patterns[1], 13841, *table, file); + len = _lou_pattern_compile(&ptn_before.chars[0], 0, &patterns[1], 13841, + *backwardTable, file); else len = _lou_pattern_compile(&ptn_before.chars[0], ptn_before.length, - &patterns[1], 13841, *table, file); + &patterns[1], 13841, *backwardTable, file); if (!len) goto CTO_BackMatch_cleanup; mrk = patterns[0] = len + 1; _lou_pattern_reverse(&patterns[1]); if (ptn_after.chars[0] == '-' && ptn_after.length == 1) - len = _lou_pattern_compile( - &ptn_after.chars[0], 0, &patterns[mrk], 13841, *table, file); + len = _lou_pattern_compile(&ptn_after.chars[0], 0, &patterns[mrk], 13841, + *backwardTable, file); else len = _lou_pattern_compile(&ptn_after.chars[0], ptn_after.length, - &patterns[mrk], 13841, *table, file); + &patterns[mrk], 13841, *backwardTable, file); if (!len) goto CTO_BackMatch_cleanup; len += mrk; if (!allocateSpaceInTranslationTable( - file, &patternOffset, len * sizeof(widechar), table)) + file, &patternOffset, len * sizeof(widechar), backwardTable)) goto CTO_BackMatch_cleanup; // allocateSpaceInTranslationTable may have moved table, so make sure rule is // still valid - rule = (TranslationTableRule *)&(*table)->ruleArea[ruleOffset]; - memcpy(&(*table)->ruleArea[patternOffset], patterns, len * sizeof(widechar)); + rule = (TranslationTableRule *)&(*backwardTable)->ruleArea[ruleOffset]; + memcpy(&(*backwardTable)->ruleArea[patternOffset], patterns, + len * sizeof(widechar)); rule->patterns = patternOffset; ok = 1; CTO_BackMatch_cleanup: @@ -3213,178 +3934,24 @@ case CTO_EndMode: case CTO_BegModePhrase: case CTO_EndModePhrase: - case CTO_LenModePhrase: { - TranslationTableCharacterAttributes mode; - int i; - switch (opcode) { - case CTO_CapsLetter: - case CTO_BegCapsWord: - case CTO_EndCapsWord: - case CTO_BegCaps: - case CTO_EndCaps: - case CTO_BegCapsPhrase: - case CTO_EndCapsPhrase: - case CTO_LenCapsPhrase: - mode = CTC_UpperCase; - i = 0; - opcode += (CTO_ModeLetter - CTO_CapsLetter); - break; - default: - if (!getToken(file, &token, "attribute name")) return 0; - if (!(*table)->characterClasses && !allocateCharacterClasses(*table)) { - return 0; - } - const CharacterClass *characterClass = findCharacterClass(&token, *table); - if (!characterClass) { - characterClass = - addCharacterClass(file, token.chars, token.length, *table, 1); - if (!characterClass) return 0; - } - mode = characterClass->attribute; - if (!(mode == CTC_UpperCase || mode == CTC_Digit) && mode >= CTC_Space && - mode <= CTC_LitDigit) { - compileError(file, - "mode must be \"uppercase\", \"digit\", or a custom " - "attribute name."); - return 0; - } - /* check if this mode is already defined and if the number of modes does - * not exceed the maximal number */ - if (mode == CTC_UpperCase) - i = 0; - else { - for (i = 1; i < MAX_MODES && (*table)->modes[i].value; i++) { - if ((*table)->modes[i].mode == mode) { - break; - } - } - if (i == MAX_MODES) { - compileError(file, "Max number of modes (%i) reached", MAX_MODES); - return 0; - } - } + case CTO_LenModePhrase: + if (forwardTable && !nofor) { + if (!compileModeIndicator(file, opcode, 1, forwardTable)) return 0; } - if (!(*table)->modes[i].value) - (*table)->modes[i] = (EmphasisClass){ plain_text, mode, - 0x1 << (MAX_EMPH_CLASSES + i), MAX_EMPH_CLASSES + i }; - switch (opcode) { - case CTO_BegModePhrase: { - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "first word capital sign", - // when mode is not caps (i != 0), provide enough information - // for back-translator to be able to recognize and ignore the - // indicator (but it won't be able to determine the mode) - i == 0 ? CTO_BegCapsPhrase : CTO_BegModePhrase, &ruleOffset, - noback, nofor, table)) - return 0; - (*table)->emphRules[MAX_EMPH_CLASSES + i][begPhraseOffset] = ruleOffset; - return 1; + if (backwardTable && !noback) { + file->linepos = lineposAfterOpcode; + if (!compileModeIndicator(file, opcode, 0, backwardTable)) return 0; } - case CTO_EndModePhrase: { - TranslationTableOffset ruleOffset; - switch (compileBeforeAfter(file)) { - case 1: // before - if ((*table)->emphRules[MAX_EMPH_CLASSES + i][endPhraseAfterOffset]) { - compileError( - file, "Capital sign after last word already defined."); - return 0; - } - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - if (!compileBrailleIndicator(file, "capital sign before last word", - i == 0 ? CTO_EndCapsPhraseBefore : CTO_EndModePhrase, - &ruleOffset, noback, nofor, table)) - return 0; - (*table)->emphRules[MAX_EMPH_CLASSES + i][endPhraseBeforeOffset] = - ruleOffset; - return 1; - case 2: // after - if ((*table)->emphRules[MAX_EMPH_CLASSES + i] - [endPhraseBeforeOffset]) { - compileError( - file, "Capital sign before last word already defined."); - return 0; - } - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - if (!compileBrailleIndicator(file, "capital sign after last word", - i == 0 ? CTO_EndCapsPhraseAfter : CTO_EndModePhrase, - &ruleOffset, noback, nofor, table)) - return 0; - (*table)->emphRules[MAX_EMPH_CLASSES + i][endPhraseAfterOffset] = - ruleOffset; - return 1; - default: // error - compileError(file, "Invalid lastword indicator location."); - return 0; - } - return 0; + return 1; + case CTO_EmphClass: + if (forwardTable && !nofor) { + if (!compileEmphClass(file, forwardTable)) return 0; } - case CTO_BegMode: { - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "first letter capital sign", - i == 0 ? CTO_BegCaps : CTO_BegMode, &ruleOffset, noback, - nofor, table)) - return 0; - (*table)->emphRules[MAX_EMPH_CLASSES + i][begOffset] = ruleOffset; - return 1; + if (backwardTable && !noback) { + file->linepos = lineposAfterOpcode; + if (!compileEmphClass(file, backwardTable)) return 0; } - case CTO_EndMode: { - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "last letter capital sign", - i == 0 ? CTO_EndCaps : CTO_EndMode, &ruleOffset, noback, - nofor, table)) - return 0; - (*table)->emphRules[MAX_EMPH_CLASSES + i][endOffset] = ruleOffset; - return 1; - } - case CTO_ModeLetter: { - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "single letter capital sign", - i == 0 ? CTO_CapsLetter : CTO_ModeLetter, &ruleOffset, noback, - nofor, table)) - return 0; - (*table)->emphRules[MAX_EMPH_CLASSES + i][letterOffset] = ruleOffset; - return 1; - } - case CTO_BegModeWord: { - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "capital word", - i == 0 ? CTO_BegCapsWord : CTO_BegModeWord, &ruleOffset, - noback, nofor, table)) - return 0; - (*table)->emphRules[MAX_EMPH_CLASSES + i][begWordOffset] = ruleOffset; - return 1; - } - case CTO_EndModeWord: { - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "capital word stop", - i == 0 ? CTO_EndCapsWord : CTO_EndModeWord, &ruleOffset, - noback, nofor, table)) - return 0; - (*table)->emphRules[MAX_EMPH_CLASSES + i][endWordOffset] = ruleOffset; - return 1; - } - case CTO_LenModePhrase: - return (*table)->emphRules[MAX_EMPH_CLASSES + i][lenPhraseOffset] = - compileNumber(file); - default: - break; - } - break; - } + return 1; /* these 8 general purpose emphasis opcodes are compiled further down to more * specific internal opcodes: @@ -3397,88 +3964,6 @@ * - endemphphrase * - lenemphphrase */ - case CTO_EmphClass: - if (!getToken(file, &emphClass, "emphasis class")) { - compileError(file, "emphclass must be followed by a valid class name."); - return 0; - } - int k, i; - char *s = malloc(sizeof(char) * (emphClass.length + 1)); - for (k = 0; k < emphClass.length; k++) s[k] = (char)emphClass.chars[k]; - s[k++] = '\0'; - for (i = 0; i < MAX_EMPH_CLASSES && (*table)->emphClassNames[i]; i++) - if (strcmp(s, (*table)->emphClassNames[i]) == 0) { - _lou_logMessage(LOU_LOG_DEBUG, "Duplicate emphasis class: %s", s); - free(s); - return 1; - } - if (i == MAX_EMPH_CLASSES) { - _lou_logMessage(LOU_LOG_ERROR, - "Max number of emphasis classes (%i) reached", MAX_EMPH_CLASSES); - errorCount++; - free(s); - return 0; - } - switch (i) { - /* For backwards compatibility (i.e. because programs will assume - * the first 3 typeform bits are `italic', `underline' and `bold') - * we require that the first 3 emphclass definitions are (in that - * order): - * - * emphclass italic - * emphclass underline - * emphclass bold - * - * While it would be possible to use the emphclass opcode only for - * defining _additional_ classes (not allowing for them to be called - * italic, underline or bold), thereby reducing the amount of - * boilerplate, we deliberately choose not to do that in order to - * not give italic, underline and bold any special status. The - * hope is that eventually all programs will use liblouis for - * emphasis the recommended way (i.e. by looking up the supported - * typeforms in the documentation or API) so that we can drop this - * restriction. - */ - case 0: - if (strcmp(s, "italic") != 0) { - _lou_logMessage(LOU_LOG_ERROR, - "First emphasis class must be \"italic\" but got " - "%s", - s); - errorCount++; - free(s); - return 0; - } - break; - case 1: - if (strcmp(s, "underline") != 0) { - _lou_logMessage(LOU_LOG_ERROR, - "Second emphasis class must be \"underline\" but " - "got " - "%s", - s); - errorCount++; - free(s); - return 0; - } - break; - case 2: - if (strcmp(s, "bold") != 0) { - _lou_logMessage(LOU_LOG_ERROR, - "Third emphasis class must be \"bold\" but got " - "%s", - s); - errorCount++; - free(s); - return 0; - } - break; - } - (*table)->emphClassNames[i] = s; - (*table)->emphClasses[i] = (EmphasisClass){ emph_1 - << i, /* relies on the order of typeforms emph_1..emph_10 */ - 0, 0x1 << i, i }; - return 1; case CTO_EmphLetter: case CTO_BegEmphWord: case CTO_EndEmphWord: @@ -3488,401 +3973,267 @@ case CTO_EndEmphPhrase: case CTO_LenEmphPhrase: case CTO_EmphModeChars: - case CTO_NoEmphChars: { - if (!getToken(file, &token, "emphasis class")) return 0; - if (!parseChars(file, &emphClass, &token)) return 0; - char *s = malloc(sizeof(char) * (emphClass.length + 1)); - int k, i; - for (k = 0; k < emphClass.length; k++) s[k] = (char)emphClass.chars[k]; - s[k++] = '\0'; - for (i = 0; i < MAX_EMPH_CLASSES && (*table)->emphClassNames[i]; i++) - if (strcmp(s, (*table)->emphClassNames[i]) == 0) break; - if (i == MAX_EMPH_CLASSES || !(*table)->emphClassNames[i]) { - _lou_logMessage(LOU_LOG_ERROR, "Emphasis class %s not declared", s); - errorCount++; - free(s); - return 0; + case CTO_NoEmphChars: + if (forwardTable && !nofor) { + if (!compileEmphIndicator(file, opcode, 1, forwardTable)) return 0; } - int ok = 0; - switch (opcode) { - case CTO_EmphLetter: { - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - // provide enough information for back-translator to be able to recognize - // and ignore the indicator (but it won't be able to determine the - // emphasis class) - if (!compileBrailleIndicator(file, "single letter", CTO_EmphLetter, - &ruleOffset, noback, nofor, table)) - break; - (*table)->emphRules[i][letterOffset] = ruleOffset; - ok = 1; - break; + if (backwardTable && !noback) { + file->linepos = lineposAfterOpcode; + if (!compileEmphIndicator(file, opcode, 0, backwardTable)) return 0; } - case CTO_BegEmphWord: { - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "word", CTO_BegEmphWord, &ruleOffset, - noback, nofor, table)) - break; - (*table)->emphRules[i][begWordOffset] = ruleOffset; - ok = 1; - break; - } - case CTO_EndEmphWord: { - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "word stop", CTO_EndEmphWord, - &ruleOffset, noback, nofor, table)) - break; - (*table)->emphRules[i][endWordOffset] = ruleOffset; - ok = 1; - break; - } - case CTO_BegEmph: { - /* fail if both begemph and any of begemphphrase or begemphword are - * defined */ - if ((*table)->emphRules[i][begWordOffset] || - (*table)->emphRules[i][begPhraseOffset]) { - compileError(file, - "Cannot define emphasis for both no context and word or " - "phrase context, i.e. cannot have both begemph and " - "begemphword or begemphphrase."); - break; - } - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "first letter", CTO_BegEmph, - &ruleOffset, noback, nofor, table)) - break; - (*table)->emphRules[i][begOffset] = ruleOffset; - ok = 1; - break; - } - case CTO_EndEmph: { - if ((*table)->emphRules[i][endWordOffset] || - (*table)->emphRules[i][endPhraseBeforeOffset] || - (*table)->emphRules[i][endPhraseAfterOffset]) { - compileError(file, - "Cannot define emphasis for both no context and word or " - "phrase context, i.e. cannot have both endemph and " - "endemphword or endemphphrase."); - break; - } - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "last letter", CTO_EndEmph, - &ruleOffset, noback, nofor, table)) - break; - (*table)->emphRules[i][endOffset] = ruleOffset; - ok = 1; - break; - } - case CTO_BegEmphPhrase: { - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "first word", CTO_BegEmphPhrase, - &ruleOffset, noback, nofor, table)) - break; - (*table)->emphRules[i][begPhraseOffset] = ruleOffset; - ok = 1; - break; - } - case CTO_EndEmphPhrase: - switch (compileBeforeAfter(file)) { - case 1: { // before - if ((*table)->emphRules[i][endPhraseAfterOffset]) { - compileError(file, "last word after already defined."); - break; - } - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "last word before", - CTO_EndEmphPhrase, &ruleOffset, noback, nofor, table)) - break; - (*table)->emphRules[i][endPhraseBeforeOffset] = ruleOffset; - ok = 1; - break; - } - case 2: { // after - if ((*table)->emphRules[i][endPhraseBeforeOffset]) { - compileError(file, "last word before already defined."); - break; - } - // not passing pointer to location inside table because - // compileBrailleIndicator may reallocate table - TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "last word after", - CTO_EndEmphPhrase, &ruleOffset, noback, nofor, table)) - break; - (*table)->emphRules[i][endPhraseAfterOffset] = ruleOffset; - ok = 1; - break; - } - default: // error - compileError(file, "Invalid lastword indicator location."); - break; - } - break; - case CTO_LenEmphPhrase: - if (((*table)->emphRules[i][lenPhraseOffset] = compileNumber(file))) - ok = 1; - break; - case CTO_EmphModeChars: { - if (!getRuleCharsText(file, &ruleChars)) break; - widechar *emphmodechars = (*table)->emphModeChars[i]; - int len; - for (len = 0; len < EMPHMODECHARSSIZE && emphmodechars[len]; len++) - ; - if (len + ruleChars.length > EMPHMODECHARSSIZE) { - compileError(file, "More than %d characters", EMPHMODECHARSSIZE); - break; - } - ok = 1; - for (int k = 0; k < ruleChars.length; k++) { - if (!getChar(ruleChars.chars[k], *table, NULL)) { - compileError(file, "Emphasis mode character undefined"); - ok = 0; - break; - } - emphmodechars[len++] = ruleChars.chars[k]; - } - break; - } - case CTO_NoEmphChars: { - if (!getRuleCharsText(file, &ruleChars)) break; - widechar *noemphchars = (*table)->noEmphChars[i]; - int len; - for (len = 0; len < NOEMPHCHARSSIZE && noemphchars[len]; len++) - ; - if (len + ruleChars.length > NOEMPHCHARSSIZE) { - compileError(file, "More than %d characters", NOEMPHCHARSSIZE); - break; - } - ok = 1; - for (int k = 0; k < ruleChars.length; k++) { - if (!getChar(ruleChars.chars[k], *table, NULL)) { - compileError(file, "Character undefined"); - ok = 0; - break; - } - noemphchars[len++] = ruleChars.chars[k]; - } - break; - } - default: - break; - } - free(s); - return ok; - } + return 1; case CTO_LetterSign: { // not passing pointer to location inside table because // compileBrailleIndicator may reallocate table TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "letter sign", CTO_LetterSign, &ruleOffset, - noback, nofor, table)) - return 0; - (*table)->letterSign = ruleOffset; + if (forwardTable && !nofor) { + if (!compileBrailleIndicator(file, "letter sign", CTO_LetterSign, + &ruleOffset, 1, forwardTable)) + return 0; + (*forwardTable)->letterSign = ruleOffset; + } + if (backwardTable && !noback) { + file->linepos = lineposAfterOpcode; + if (!compileBrailleIndicator(file, "letter sign", CTO_LetterSign, + &ruleOffset, 0, backwardTable)) + return 0; + (*backwardTable)->letterSign = ruleOffset; + } return 1; } case CTO_NoLetsignBefore: + if (!forwardTable) return 1; if (!getRuleCharsText(file, &ruleChars)) return 0; - if (((*table)->noLetsignBeforeCount + ruleChars.length) > LETSIGNBEFORESIZE) { + if (((*forwardTable)->noLetsignBeforeCount + ruleChars.length) > + LETSIGNBEFORESIZE) { compileError(file, "More than %d characters", LETSIGNBEFORESIZE); return 0; } for (int k = 0; k < ruleChars.length; k++) - (*table)->noLetsignBefore[(*table)->noLetsignBeforeCount++] = + (*forwardTable) + ->noLetsignBefore[(*forwardTable)->noLetsignBeforeCount++] = ruleChars.chars[k]; return 1; case CTO_NoLetsign: + if (!forwardTable) return 1; if (!getRuleCharsText(file, &ruleChars)) return 0; - if (((*table)->noLetsignCount + ruleChars.length) > LETSIGNSIZE) { + if (((*forwardTable)->noLetsignCount + ruleChars.length) > LETSIGNSIZE) { compileError(file, "More than %d characters", LETSIGNSIZE); return 0; } for (int k = 0; k < ruleChars.length; k++) - (*table)->noLetsign[(*table)->noLetsignCount++] = ruleChars.chars[k]; + (*forwardTable)->noLetsign[(*forwardTable)->noLetsignCount++] = + ruleChars.chars[k]; return 1; case CTO_NoLetsignAfter: + if (!forwardTable) return 1; if (!getRuleCharsText(file, &ruleChars)) return 0; - if (((*table)->noLetsignAfterCount + ruleChars.length) > LETSIGNAFTERSIZE) { + if (((*forwardTable)->noLetsignAfterCount + ruleChars.length) > + LETSIGNAFTERSIZE) { compileError(file, "More than %d characters", LETSIGNAFTERSIZE); return 0; } for (int k = 0; k < ruleChars.length; k++) - (*table)->noLetsignAfter[(*table)->noLetsignAfterCount++] = + (*forwardTable)->noLetsignAfter[(*forwardTable)->noLetsignAfterCount++] = ruleChars.chars[k]; return 1; case CTO_NumberSign: { // not passing pointer to location inside table because // compileBrailleIndicator may reallocate table TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "number sign", CTO_NumberSign, &ruleOffset, - noback, nofor, table)) - return 0; - (*table)->numberSign = ruleOffset; + if (forwardTable && !nofor) { + if (!compileBrailleIndicator(file, "number sign", CTO_NumberSign, + &ruleOffset, 1, forwardTable)) + return 0; + (*forwardTable)->numberSign = ruleOffset; + } + if (backwardTable && !noback) { + file->linepos = lineposAfterOpcode; + if (!compileBrailleIndicator(file, "number sign", CTO_NumberSign, + &ruleOffset, 0, backwardTable)) + return 0; + (*backwardTable)->numberSign = ruleOffset; + } return 1; } case CTO_NoNumberSign: { // not passing pointer to location inside table because // compileBrailleIndicator may reallocate table TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "no number sign", CTO_NoNumberSign, - &ruleOffset, noback, nofor, table)) - return 0; - (*table)->noNumberSign = ruleOffset; + if (forwardTable && !nofor) { + if (!compileBrailleIndicator(file, "no number sign", CTO_NoNumberSign, + &ruleOffset, 1, forwardTable)) + return 0; + (*forwardTable)->noNumberSign = ruleOffset; + } + if (backwardTable && !noback) { + file->linepos = lineposAfterOpcode; + if (!compileBrailleIndicator(file, "no number sign", CTO_NoNumberSign, + &ruleOffset, 0, backwardTable)) + return 0; + (*backwardTable)->noNumberSign = ruleOffset; + } return 1; } - case CTO_NumericModeChars: - if (!getRuleCharsText(file, &ruleChars)) return 0; - for (int k = 0; k < ruleChars.length; k++) { - TranslationTableCharacter *c = getChar(ruleChars.chars[k], *table, NULL); - if (!c) { - compileError(file, "Numeric mode character undefined: %s", - _lou_showString(&ruleChars.chars[k], 1, 0)); - return 0; - } - c->attributes |= CTC_NumericMode; - (*table)->usesNumericMode = 1; - } + if (forwardTable && + !compileAttribute( + file, CTC_NumericMode, "Numeric mode", forwardTable)) + return 0; + file->linepos = lineposAfterOpcode; + if (backwardTable && + !compileAttribute( + file, CTC_NumericMode, "Numeric mode", backwardTable)) + return 0; + if (forwardTable) (*forwardTable)->usesNumericMode = 1; return 1; - case CTO_MidEndNumericModeChars: - if (!getRuleCharsText(file, &ruleChars)) return 0; - for (int k = 0; k < ruleChars.length; k++) { - TranslationTableCharacter *c = getChar(ruleChars.chars[k], *table, NULL); - if (!c) { - compileError(file, "Midendnumeric mode character undefined"); - return 0; - } - c->attributes |= CTC_MidEndNumericMode; - (*table)->usesNumericMode = 1; - } + if (forwardTable && + !compileAttribute(file, CTC_MidEndNumericMode, "Midendnumeric mode", + forwardTable)) + return 0; + file->linepos = lineposAfterOpcode; + if (backwardTable && + !compileAttribute(file, CTC_MidEndNumericMode, "Midendnumeric mode", + backwardTable)) + return 0; + if (forwardTable) (*forwardTable)->usesNumericMode = 1; return 1; - case CTO_NumericNoContractChars: - if (!getRuleCharsText(file, &ruleChars)) return 0; - for (int k = 0; k < ruleChars.length; k++) { - TranslationTableCharacter *c = getChar(ruleChars.chars[k], *table, NULL); - if (!c) { - compileError(file, "Numeric no contraction character undefined"); - return 0; - } - c->attributes |= CTC_NumericNoContract; - (*table)->usesNumericMode = 1; - } + if (forwardTable && + !compileAttribute(file, CTC_NumericNoContract, + "Numeric no contraction", forwardTable)) + return 0; + file->linepos = lineposAfterOpcode; + if (backwardTable && + !compileAttribute(file, CTC_NumericNoContract, + "Numeric no contraction", backwardTable)) + return 0; + if (forwardTable) (*forwardTable)->usesNumericMode = 1; return 1; - case CTO_NoContractSign: { // not passing pointer to location inside table because // compileBrailleIndicator may reallocate table TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "no contractions sign", CTO_NoContractSign, - &ruleOffset, noback, nofor, table)) - return 0; - (*table)->noContractSign = ruleOffset; + if (forwardTable && !nofor) { + if (!compileBrailleIndicator(file, "no contractions sign", + CTO_NoContractSign, &ruleOffset, 1, forwardTable)) + return 0; + (*forwardTable)->noContractSign = ruleOffset; + } + if (backwardTable && !noback) { + file->linepos = lineposAfterOpcode; + if (!compileBrailleIndicator(file, "no contractions sign", + CTO_NoContractSign, &ruleOffset, 1, backwardTable)) + return 0; + (*backwardTable)->noContractSign = ruleOffset; + } return 1; } case CTO_SeqDelimiter: - if (!getRuleCharsText(file, &ruleChars)) return 0; - for (int k = 0; k < ruleChars.length; k++) { - TranslationTableCharacter *c = getChar(ruleChars.chars[k], *table, NULL); - if (!c) { - compileError(file, "Sequence delimiter character undefined"); - return 0; - } - c->attributes |= CTC_SeqDelimiter; - (*table)->usesSequences = 1; - } + if (forwardTable && + !compileAttribute( + file, CTC_SeqDelimiter, "Sequence delimiter", forwardTable)) + return 0; + file->linepos = lineposAfterOpcode; + if (backwardTable && + !compileAttribute( + file, CTC_SeqDelimiter, "Sequence delimiter", backwardTable)) + return 0; + if (forwardTable) (*forwardTable)->usesSequences = 1; return 1; - case CTO_SeqBeforeChars: - if (!getRuleCharsText(file, &ruleChars)) return 0; - for (int k = 0; k < ruleChars.length; k++) { - TranslationTableCharacter *c = getChar(ruleChars.chars[k], *table, NULL); - if (!c) { - compileError(file, "Sequence before character undefined"); - return 0; - } - c->attributes |= CTC_SeqBefore; - } + if (forwardTable && + !compileAttribute( + file, CTC_SeqBefore, "Sequence before", forwardTable)) + return 0; + file->linepos = lineposAfterOpcode; + if (backwardTable && + !compileAttribute( + file, CTC_SeqBefore, "Sequence before", backwardTable)) + return 0; return 1; - case CTO_SeqAfterChars: - if (!getRuleCharsText(file, &ruleChars)) return 0; - for (int k = 0; k < ruleChars.length; k++) { - TranslationTableCharacter *c = getChar(ruleChars.chars[k], *table, NULL); - if (!c) { - compileError(file, "Sequence after character undefined"); - return 0; - } - c->attributes |= CTC_SeqAfter; - } + if (forwardTable && + !compileAttribute(file, CTC_SeqAfter, "Sequence after", forwardTable)) + return 0; + file->linepos = lineposAfterOpcode; + if (backwardTable && + !compileAttribute( + file, CTC_SeqAfter, "Sequence after", backwardTable)) + return 0; return 1; - case CTO_SeqAfterPattern: + if (!forwardTable) return 1; if (!getRuleCharsText(file, &ruleChars)) return 0; - if (((*table)->seqPatternsCount + ruleChars.length + 1) > SEQPATTERNSIZE) { + if (((*forwardTable)->seqPatternsCount + ruleChars.length + 1) > + SEQPATTERNSIZE) { compileError(file, "More than %d characters", SEQPATTERNSIZE); return 0; } for (int k = 0; k < ruleChars.length; k++) - (*table)->seqPatterns[(*table)->seqPatternsCount++] = ruleChars.chars[k]; - (*table)->seqPatterns[(*table)->seqPatternsCount++] = 0; + (*forwardTable)->seqPatterns[(*forwardTable)->seqPatternsCount++] = + ruleChars.chars[k]; + (*forwardTable)->seqPatterns[(*forwardTable)->seqPatternsCount++] = 0; return 1; - case CTO_SeqAfterExpression: + if (!forwardTable) return 1; if (!getRuleCharsText(file, &ruleChars)) return 0; if ((ruleChars.length + 1) > SEQPATTERNSIZE) { compileError(file, "More than %d characters", SEQPATTERNSIZE); return 0; } for (int k = 0; k < ruleChars.length; k++) - (*table)->seqAfterExpression[k] = ruleChars.chars[k]; - (*table)->seqAfterExpression[ruleChars.length] = 0; - (*table)->seqAfterExpressionLength = ruleChars.length; + (*forwardTable)->seqAfterExpression[k] = ruleChars.chars[k]; + (*forwardTable)->seqAfterExpression[ruleChars.length] = 0; + (*forwardTable)->seqAfterExpressionLength = ruleChars.length; return 1; - case CTO_CapsModeChars: - if (!getRuleCharsText(file, &ruleChars)) return 0; - for (int k = 0; k < ruleChars.length; k++) { - TranslationTableCharacter *c = getChar(ruleChars.chars[k], *table, NULL); - if (!c) { - compileError(file, "Capital mode character undefined"); - return 0; - } - c->attributes |= CTC_CapsMode; - (*table)->hasCapsModeChars = 1; - } + if (forwardTable && + !compileAttribute(file, CTC_CapsMode, "Capital mode", forwardTable)) + return 0; + file->linepos = lineposAfterOpcode; + if (backwardTable && + !compileAttribute(file, CTC_CapsMode, "Capital mode", backwardTable)) + return 0; + if (forwardTable) (*forwardTable)->hasCapsModeChars = 1; return 1; - case CTO_BegComp: { // not passing pointer to location inside table because // compileBrailleIndicator may reallocate table TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "begin computer braille", CTO_BegComp, - &ruleOffset, noback, nofor, table)) - return 0; - (*table)->begComp = ruleOffset; + if (forwardTable && !nofor) { + if (!compileBrailleIndicator(file, "begin computer braille", CTO_BegComp, + &ruleOffset, 1, forwardTable)) + return 0; + (*forwardTable)->begComp = ruleOffset; + } + if (backwardTable && !noback) { + file->linepos = lineposAfterOpcode; + if (!compileBrailleIndicator(file, "begin computer braille", CTO_BegComp, + &ruleOffset, 0, backwardTable)) + return 0; + (*backwardTable)->begComp = ruleOffset; + } return 1; } case CTO_EndComp: { // not passing pointer to location inside table because // compileBrailleIndicator may reallocate table TranslationTableOffset ruleOffset; - if (!compileBrailleIndicator(file, "end computer braslle", CTO_EndComp, - &ruleOffset, noback, nofor, table)) - return 0; - (*table)->endComp = ruleOffset; + if (forwardTable && !nofor) { + if (!compileBrailleIndicator(file, "end computer braille", CTO_EndComp, + &ruleOffset, 1, forwardTable)) + return 0; + (*forwardTable)->endComp = ruleOffset; + } + if (backwardTable && !noback) { + file->linepos = lineposAfterOpcode; + if (!compileBrailleIndicator(file, "end computer braille", CTO_EndComp, + &ruleOffset, 0, backwardTable)) + return 0; + (*backwardTable)->endComp = ruleOffset; + } return 1; } case CTO_NoCross: @@ -3894,7 +4245,7 @@ nocross = 1; goto doOpcode; case CTO_Syllable: - (*table)->syllables = 1; + if (forwardTable) (*forwardTable)->syllables = 1; case CTO_Always: case CTO_LargeSign: case CTO_WholeWord: @@ -3918,23 +4269,31 @@ case CTO_RepWord: if (!getRuleCharsText(file, &ruleChars)) return 0; if (!getRuleDotsPattern(file, &ruleDots)) return 0; - if (ruleDots.length == 0) - // check that all characters in a rule with `=` as second operand are - // defined (or based on another character) - for (int k = 0; k < ruleChars.length; k++) { - TranslationTableCharacter *c = - getChar(ruleChars.chars[k], *table, NULL); - if (!(c && (c->definitionRule || c->basechar))) { - compileError(file, "Character %s is not defined", - _lou_showString(&ruleChars.chars[k], 1, 0)); - return 0; + if (forwardTable && !nofor) { + if (ruleDots.length == 0) + // check that all characters in a rule with `=` as second operand are + // defined (or based on another character) + for (int k = 0; k < ruleChars.length; k++) { + TranslationTableCharacter *c = + getChar(ruleChars.chars[k], *forwardTable, NULL); + if (!(c && (c->definitionRule || c->basechar))) { + compileError(file, "Character %s is not defined", + _lou_showString(&ruleChars.chars[k], 1, 0)); + return 0; + } } - } - TranslationTableRule *r; - if (!addRule(file, opcode, &ruleChars, &ruleDots, after, before, NULL, &r, - noback, nofor, table)) - return 0; - if (nocross) r->nocross = 1; + TranslationTableRule *r; + if (!addForwardRule(file, opcode, &ruleChars, &ruleDots, forwardAfter, + forwardBefore, NULL, &r, forwardTable)) + return 0; + if (nocross) r->nocross = 1; + } + if (backwardTable && !noback && ruleDots.length > 0) { + file->linepos = lineposAfterOpcode; + if (!addBackwardRule(file, opcode, &ruleChars, &ruleDots, backwardAfter, + backwardBefore, NULL, NULL, backwardTable)) + return 0; + } return 1; // if (opcode == CTO_MidNum) // { @@ -3943,6 +4302,7 @@ // c->attributes |= CTC_NumericMode; // } case CTO_RepEndWord: + if (!forwardTable) return 1; if (!getRuleCharsText(file, &ruleChars)) return 0; CharsString dots; if (!getToken(file, &dots, "dots,dots operand")) return 0; @@ -3958,7 +4318,7 @@ // character) for (int l = 0; l < ruleChars.length; l++) { TranslationTableCharacter *c = - getChar(ruleChars.chars[l], *table, NULL); + getChar(ruleChars.chars[l], *forwardTable, NULL); if (!(c && (c->definitionRule || c->basechar))) { compileError(file, "Character %s is not defined", _lou_showString(&ruleChars.chars[l], 1, 0)); @@ -3973,27 +4333,27 @@ for (int l = 0; l < y.length; l++) ruleDots.chars[ruleDots.length++] = y.chars[l]; } - return addRule(file, opcode, &ruleChars, &ruleDots, after, before, - NULL, NULL, noback, nofor, table); + return nofor || + addForwardRule(file, opcode, &ruleChars, &ruleDots, + forwardAfter, forwardBefore, NULL, NULL, + forwardTable); } } return 0; case CTO_CompDots: case CTO_Comp6: { - TranslationTableOffset ruleOffset; + if (nofor || noback) { + compileWarning(file, "nofor and noback not allowed on comp6 rules"); + } if (!getRuleCharsText(file, &ruleChars)) return 0; if (ruleChars.length != 1) { compileError(file, "first operand must be 1 character"); return 0; } - if (nofor || noback) { - compileWarning(file, "nofor and noback not allowed on comp6 rules"); - } if (!getRuleDotsPattern(file, &ruleDots)) return 0; - if (!addRule(file, opcode, &ruleChars, &ruleDots, after, before, &ruleOffset, - NULL, noback, nofor, table)) - return 0; - return 1; + return addRule(file, opcode, &ruleChars, &ruleDots, forwardAfter, + backwardBefore, forwardAfter, backwardBefore, noback, nofor, + forwardTable, backwardTable); } case CTO_ExactDots: if (!getRuleCharsText(file, &ruleChars)) return 0; @@ -4005,19 +4365,22 @@ scratchPad.chars[k - 1] = ruleChars.chars[k]; scratchPad.length = ruleChars.length - 1; if (!parseDots(file, &ruleDots, &scratchPad)) return 0; - return addRule(file, opcode, &ruleChars, &ruleDots, after, before, NULL, NULL, - noback, nofor, table); + return addRule(file, opcode, &ruleChars, &ruleDots, forwardAfter, + backwardAfter, forwardBefore, backwardBefore, noback, nofor, + forwardTable, backwardTable); case CTO_CapsNoCont: { + if (!forwardTable) return 1; TranslationTableOffset ruleOffset; ruleChars.length = 1; ruleChars.chars[0] = 'a'; - if (!addRule(file, opcode, &ruleChars, NULL, after, before, &ruleOffset, NULL, - noback, nofor, table)) + if (!addForwardRule(file, opcode, &ruleChars, NULL, forwardAfter, + forwardAfter, &ruleOffset, NULL, forwardTable)) return 0; - (*table)->capsNoCont = ruleOffset; + (*forwardTable)->capsNoCont = ruleOffset; return 1; } case CTO_Replace: + if (!forwardTable) return 1; if (getRuleCharsText(file, &ruleChars)) { if (atEndOfLine(file)) ruleDots.length = ruleDots.chars[0] = 0; @@ -4031,40 +4394,57 @@ } } for (int k = 0; k < ruleChars.length; k++) - putChar(file, ruleChars.chars[k], table, NULL, (*table)->ruleCounter); + putChar(file, ruleChars.chars[k], forwardTable, NULL, + (*forwardTable)->ruleCounter); for (int k = 0; k < ruleDots.length; k++) - putChar(file, ruleDots.chars[k], table, NULL, (*table)->ruleCounter); - return addRule(file, opcode, &ruleChars, &ruleDots, after, before, NULL, NULL, - noback, nofor, table); + putChar(file, ruleDots.chars[k], forwardTable, NULL, + (*forwardTable)->ruleCounter); + return nofor || + addForwardRule(file, opcode, &ruleChars, &ruleDots, forwardAfter, + forwardBefore, NULL, NULL, forwardTable); case CTO_Correct: - (*table)->corrections = 1; - goto doPass; case CTO_Pass2: - if ((*table)->numPasses < 2) (*table)->numPasses = 2; - goto doPass; case CTO_Pass3: - if ((*table)->numPasses < 3) (*table)->numPasses = 3; - goto doPass; case CTO_Pass4: - if ((*table)->numPasses < 4) (*table)->numPasses = 4; - doPass: - case CTO_Context: + case CTO_Context: { if (!(nofor || noback)) { compileError(file, "%s or %s must be specified.", _lou_findOpcodeName(CTO_NoFor), _lou_findOpcodeName(CTO_NoBack)); return 0; } - return compilePassOpcode(file, opcode, noback, nofor, table); + TranslationTableHeader **table = noback ? forwardTable : backwardTable; + if (!table) return 1; + switch (opcode) { + case CTO_Correct: + (*table)->corrections = 1; + break; + case CTO_Pass2: + if ((*table)->numPasses < 2) (*table)->numPasses = 2; + break; + case CTO_Pass3: + if ((*table)->numPasses < 3) (*table)->numPasses = 3; + break; + case CTO_Pass4: + if ((*table)->numPasses < 4) (*table)->numPasses = 4; + break; + case CTO_Context: + default: + break; + } + return compilePassOpcode(file, opcode, noback, table); + } case CTO_Contraction: case CTO_NoCont: case CTO_CompBrl: case CTO_Literal: + if (!forwardTable) return 1; if (!getRuleCharsText(file, &ruleChars)) return 0; // check that all characters in a compbrl, contraction, // nocont or literal rule are defined (or based on another // character) for (int k = 0; k < ruleChars.length; k++) { - TranslationTableCharacter *c = getChar(ruleChars.chars[k], *table, NULL); + TranslationTableCharacter *c = + getChar(ruleChars.chars[k], *forwardTable, NULL); if (!(c && (c->definitionRule || c->basechar))) { compileError(file, "Character %s is not defined", _lou_showString(&ruleChars.chars[k], 1, 0)); @@ -4075,9 +4455,11 @@ compileWarning(file, "literal is deprecated, use compbrl instead"); opcode = CTO_CompBrl; } - return addRule(file, opcode, &ruleChars, NULL, after, before, NULL, NULL, - noback, nofor, table); + return nofor || + addForwardRule(file, opcode, &ruleChars, NULL, forwardAfter, + forwardBefore, NULL, NULL, forwardTable); case CTO_MultInd: { + if (!backwardTable) return 1; ruleChars.length = 0; if (!getToken(file, &token, "multiple braille indicators") || !parseDots(file, &cells, &token)) @@ -4096,212 +4478,85 @@ ruleChars.chars[ruleChars.length++] = (widechar)opcode; if (atEndOfLine(file)) break; } - return addRule(file, CTO_MultInd, &ruleChars, &cells, after, before, NULL, - NULL, noback, nofor, table); + return noback || + addBackwardRule(file, CTO_MultInd, &ruleChars, &cells, backwardAfter, + backwardBefore, NULL, NULL, backwardTable); } - case CTO_Class: compileWarning(file, "class is deprecated, use attribute instead"); - case CTO_Attribute: { + case CTO_Attribute: if (nofor || noback) { compileWarning( file, "nofor and noback not allowed before class/attribute"); } + TranslationTableHeader **table = forwardTable ? forwardTable : backwardTable; if ((opcode == CTO_Class && (*table)->usesAttributeOrClass == 1) || (opcode == CTO_Attribute && (*table)->usesAttributeOrClass == 2)) { compileError(file, "attribute and class rules must not be both present in a table"); return 0; } - if (opcode == CTO_Class) - (*table)->usesAttributeOrClass = 2; - else - (*table)->usesAttributeOrClass = 1; - if (!getToken(file, &token, "attribute name")) { - compileError(file, "Expected %s", "attribute name"); + (*table)->usesAttributeOrClass = opcode == CTO_Class ? 2 : 1; + if (forwardTable && !compileNamedAttribute(file, opcode, forwardTable)) return 0; - } - if (!(*table)->characterClasses && !allocateCharacterClasses(*table)) { + file->linepos = lineposAfterOpcode; + if (backwardTable && !compileNamedAttribute(file, opcode, backwardTable)) return 0; - } - - TranslationTableCharacterAttributes attribute = 0; - { - int attrNumber = -1; - switch (token.chars[0]) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - attrNumber = token.chars[0] - '0'; - break; - } - if (attrNumber >= 0) { - if (opcode == CTO_Class) { - compileError(file, - "Invalid class name: may not contain digits, use " - "attribute instead of class"); - return 0; - } - if (token.length > 1 || attrNumber > 7) { - compileError(file, - "Invalid attribute name: must be a digit between 0 and 7 " - "or a word containing only letters"); - return 0; - } - if (!(*table)->numberedAttributes[attrNumber]) - // attribute not used before yet: assign it a value - (*table)->numberedAttributes[attrNumber] = - getNextNumberedAttribute(*table); - attribute = (*table)->numberedAttributes[attrNumber]; - } else { - const CharacterClass *namedAttr = findCharacterClass(&token, *table); - if (!namedAttr) { - // no class with that name: create one - namedAttr = addCharacterClass( - file, &token.chars[0], token.length, *table, 1); - if (!namedAttr) return 0; - } - // there is a class with that name or a new class was successfully - // created - attribute = namedAttr->attribute; - if (attribute == CTC_UpperCase || attribute == CTC_LowerCase) - attribute |= CTC_Letter; - } - } - CharsString characters; - if (!getCharacters(file, &characters)) return 0; - for (int i = 0; i < characters.length; i++) { - // get the character from the table, or if it is not defined yet, - // define it - TranslationTableCharacter *character = putChar( - file, characters.chars[i], table, NULL, (*table)->ruleCounter); - // set the attribute - character->attributes |= attribute; - // also set the attribute on the associated dots (if any) - if (character->basechar) - character = (TranslationTableCharacter *)&(*table) - ->ruleArea[character->basechar]; - if (character->definitionRule) { - TranslationTableRule *defRule = - (TranslationTableRule *)&(*table) - ->ruleArea[character->definitionRule]; - if (defRule->dotslen == 1) { - TranslationTableCharacter *dots = - getDots(defRule->charsdots[defRule->charslen], *table); - if (dots) dots->attributes |= attribute; - } - } - } - (*table)->ruleCounter++; return 1; - } { - TranslationTableCharacterAttributes *attributes; const CharacterClass *class; case CTO_After: - attributes = &after; - goto doBeforeAfter; case CTO_Before: - attributes = &before; - doBeforeAfter: - if (!(*table)->characterClasses) { - if (!allocateCharacterClasses(*table)) return 0; - } if (!getToken(file, &token, "attribute name")) return 0; - if (!(class = findCharacterClass(&token, *table))) { - compileError(file, "attribute not defined"); - return 0; + if (forwardTable) { + if (!(*forwardTable)->characterClasses) { + if (!allocateCharacterClasses(*forwardTable)) return 0; + } + if (!(class = findCharacterClass(&token, *forwardTable))) { + compileError(file, "attribute not defined"); + return 0; + } + if (opcode == CTO_After) + forwardAfter |= class->attribute; + else + forwardBefore |= class->attribute; } - *attributes |= class->attribute; + if (backwardTable) { + if (!(*backwardTable)->characterClasses) { + if (!allocateCharacterClasses(*backwardTable)) return 0; + } + if (!(class = findCharacterClass(&token, *backwardTable))) { + compileError(file, "attribute not defined"); + return 0; + } + if (opcode == CTO_After) + backwardAfter |= class->attribute; + else + backwardBefore |= class->attribute; + } goto doOpcode; } case CTO_Base: if (nofor || noback) { compileWarning(file, "nofor and noback not allowed before base"); } - if (!getToken(file, &token, "attribute name")) { - compileError( - file, "base opcode must be followed by a valid attribute name."); - return 0; - } - if (!(*table)->characterClasses && !allocateCharacterClasses(*table)) { - return 0; - } - const CharacterClass *mode = findCharacterClass(&token, *table); - if (!mode) { - mode = addCharacterClass(file, token.chars, token.length, *table, 1); - if (!mode) return 0; - } - if (!(mode->attribute == CTC_UpperCase || mode->attribute == CTC_Digit) && - mode->attribute >= CTC_Space && mode->attribute <= CTC_LitDigit) { - compileError(file, - "base opcode must be followed by \"uppercase\", \"digit\", or a " - "custom attribute name."); - return 0; - } - if (!getRuleCharsText(file, &token)) return 0; - if (token.length != 1) { - compileError(file, - "Exactly one character followed by one base character is " - "required."); - return 0; - } - TranslationTableOffset characterOffset; - TranslationTableCharacter *character = putChar( - file, token.chars[0], table, &characterOffset, (*table)->ruleCounter); - if (!getRuleCharsText(file, &token)) return 0; - if (token.length != 1) { - compileError(file, "Exactly one base character is required."); - return 0; - } - TranslationTableOffset basechar; - putChar(file, token.chars[0], table, &basechar, (*table)->ruleCounter); - // putChar may have moved table, so make sure character is still valid - character = (TranslationTableCharacter *)&(*table)->ruleArea[characterOffset]; - if (character->basechar) { - if (character->basechar == basechar && - character->mode == mode->attribute) { - _lou_logMessage(LOU_LOG_DEBUG, "%s:%d: Duplicate base rule.", - file->fileName, file->lineNumber); - } else { - _lou_logMessage(LOU_LOG_DEBUG, - "%s:%d: A different base rule already exists for this " - "character (%s). The existing rule will take precedence " - "over the new one.", - file->fileName, file->lineNumber, - printSource(file->sourceFile, character->sourceFile, - character->sourceLine)); - } - } else { - character->basechar = basechar; - character->mode = mode->attribute; - character->sourceFile = file->sourceFile; - character->sourceLine = file->lineNumber; - character->ruleIndex = (*table)->ruleCounter; - /* some other processing is done at the end of the compilation, in - * finalizeTable() */ - } - (*table)->ruleCounter++; + if (forwardTable && !compileBase(file, forwardTable)) return 0; + file->linepos = lineposAfterOpcode; + if (backwardTable && !compileBase(file, backwardTable)) return 0; return 1; case CTO_EmpMatchBefore: - before |= CTC_EmpMatch; + if (forwardTable) forwardBefore |= CTC_EmpMatch; + if (backwardTable) backwardBefore |= CTC_EmpMatch; goto doOpcode; case CTO_EmpMatchAfter: - after |= CTC_EmpMatch; + if (forwardTable) forwardAfter |= CTC_EmpMatch; + if (backwardTable) backwardAfter |= CTC_EmpMatch; goto doOpcode; - case CTO_SwapCc: case CTO_SwapCd: case CTO_SwapDd: - return compileSwap(file, opcode, noback, nofor, table); + return compileSwap(file, opcode, noback, nofor, forwardTable, backwardTable); case CTO_Hyphen: case CTO_DecPoint: // case CTO_Apostrophe: @@ -4314,8 +4569,9 @@ "required."); return 0; } - return addRule(file, opcode, &ruleChars, &ruleDots, after, before, NULL, NULL, - noback, nofor, table); + return addRule(file, opcode, &ruleChars, &ruleDots, forwardAfter, + backwardAfter, forwardBefore, backwardBefore, noback, nofor, + forwardTable, backwardTable); // if (opcode == CTO_DecPoint) // { // TranslationTableCharacter *c = @@ -4508,7 +4764,7 @@ if (table->noLetsignCount < LETSIGNSIZE) table->noLetsign[table->noLetsignCount++] = rule->charsdots[0]; - otherRule = &rule->charsnext; + otherRule = &rule->next; } } characterOffset = character->next; @@ -4521,7 +4777,7 @@ // the compilation of tables with a lot of context rules, but the good news is that // translation speed is not affected. for (unsigned long int i = 0; i < HASHNUM; i++) { - TranslationTableOffset *p = &table->forRules[i]; + TranslationTableOffset *p = &table->rules[i]; while (*p) { TranslationTableRule *rule = (TranslationTableRule *)&table->ruleArea[*p]; // For now only move the rules that we know are case-sensitive, namely @@ -4534,7 +4790,7 @@ // letters if (hash != i) { // compute new position - TranslationTableOffset *insert_at = &table->forRules[hash]; + TranslationTableOffset *insert_at = &table->rules[hash]; while (*insert_at) { TranslationTableRule *r = (TranslationTableRule *)&table->ruleArea[*insert_at]; @@ -4542,18 +4798,18 @@ break; else if (rule->charslen == r->charslen && r->opcode == CTO_Always) break; - insert_at = &r->charsnext; + insert_at = &r->next; } // remove rule from current list and insert it at the correct position // in the new list - TranslationTableOffset next = rule->charsnext; - rule->charsnext = *insert_at; + TranslationTableOffset next = rule->next; + rule->next = *insert_at; *insert_at = *p; *p = next; continue; } } - p = &rule->charsnext; + p = &rule->next; } } table->finalized = 1; @@ -4561,8 +4817,8 @@ } static int -compileString(const char *inString, TranslationTableHeader **table, - DisplayTableHeader **displayTable) { +compileString(const char *inString, TranslationTableHeader **forwardTable, + TranslationTableHeader **backwardTable, DisplayTableHeader **displayTable) { /* This function can be used to make changes to tables on the fly. */ int k; FileInfo file; @@ -4576,11 +4832,12 @@ for (k = 0; k < MAXSTRING - 1 && inString[k]; k++) file.line[k] = inString[k]; file.line[k] = 0; file.linelen = k; - if (table && *table && (*table)->finalized) { + if ((forwardTable && *forwardTable && (*forwardTable)->finalized) || + (backwardTable && *backwardTable && (*backwardTable)->finalized)) { compileError(&file, "Table is finalized"); return 0; } - return compileRule(&file, table, displayTable, NULL); + return compileRule(&file, forwardTable, backwardTable, displayTable, NULL); } static int @@ -4857,21 +5114,25 @@ * */ static int -compileFile(const char *fileName, TranslationTableHeader **table, - DisplayTableHeader **displayTable) { +compileFile(const char *fileName, TranslationTableHeader **forwardTable, + TranslationTableHeader **backwardTable, DisplayTableHeader **displayTable) { FileInfo file; fileCount++; file.fileName = fileName; - if (table) { - int i; - for (i = 0; (*table)->sourceFiles[i]; i++) - ; - if (i >= MAX_SOURCE_FILES) { - _lou_logMessage(LOU_LOG_WARN, "Max number of source files (%i) reached", - MAX_SOURCE_FILES); - file.sourceFile = NULL; - } else { - file.sourceFile = (*table)->sourceFiles[i] = strdup(fileName); + { + TranslationTableHeader **table = forwardTable; + if (!table) table = backwardTable; + if (table) { + int i; + for (i = 0; (*table)->sourceFiles[i]; i++) + ; + if (i >= MAX_SOURCE_FILES) { + _lou_logMessage(LOU_LOG_WARN, "Max number of source files (%i) reached", + MAX_SOURCE_FILES); + file.sourceFile = NULL; + } else { + file.sourceFile = (*table)->sourceFiles[i] = strdup(fileName); + } } } file.encoding = noEncoding; @@ -4881,7 +5142,8 @@ // the scope of a macro is the current file (after the macro definition) const MacroList *inscopeMacros = NULL; while (_lou_getALine(&file)) - if (!compileRule(&file, table, displayTable, &inscopeMacros)) { + if (!compileRule(&file, forwardTable, backwardTable, displayTable, + &inscopeMacros)) { if (!errorCount) compileError(&file, "Rule could not be compiled"); break; } @@ -4925,7 +5187,8 @@ */ static int includeFile(const FileInfo *file, CharsString *includedFile, - TranslationTableHeader **table, DisplayTableHeader **displayTable) { + TranslationTableHeader **forwardTable, TranslationTableHeader **backwardTable, + DisplayTableHeader **displayTable) { int k; char includeThis[MAXSTRING]; char **tableFiles; @@ -4948,7 +5211,7 @@ includeThis); return 0; } - rv = compileFile(*tableFiles, table, displayTable); + rv = compileFile(*tableFiles, forwardTable, backwardTable, displayTable); lou_freeTableFiles(tableFiles); if (!rv) _lou_logMessage(LOU_LOG_ERROR, "%s:%d: Error in included file", file->fileName, @@ -4962,13 +5225,15 @@ */ static int compileTable(const char *tableList, const char *displayTableList, - TranslationTableHeader **translationTable, DisplayTableHeader **displayTable) { + TranslationTableHeader **forwardTable, TranslationTableHeader **backwardTable, + DisplayTableHeader **displayTable) { char **tableFiles; char **subTable; - if (translationTable && !tableList) return 0; + if ((forwardTable || backwardTable) && !tableList) return 0; if (displayTable && !displayTableList) return 0; - if (!translationTable && !displayTable) return 0; - if (translationTable) *translationTable = NULL; + if (!forwardTable && !backwardTable && !displayTable) return 0; + if (forwardTable) *forwardTable = NULL; + if (backwardTable) *backwardTable = NULL; if (displayTable) *displayTable = NULL; errorCount = warningCount = fileCount = 0; if (!opcodeLengths[0]) { @@ -4976,13 +5241,18 @@ for (opcode = 0; opcode < CTO_None; opcode++) opcodeLengths[opcode] = (short)strlen(opcodeNames[opcode]); } - if (translationTable) allocateTranslationTable(NULL, translationTable); + if (forwardTable) allocateTranslationTable(NULL, forwardTable); + if (backwardTable) allocateTranslationTable(NULL, backwardTable); if (displayTable) allocateDisplayTable(NULL, displayTable); - - if (translationTable) { - (*translationTable)->emphClassNames[0] = NULL; - (*translationTable)->characterClasses = NULL; - (*translationTable)->ruleNames = NULL; + if (forwardTable) { + (*forwardTable)->emphClassNames[0] = NULL; + (*forwardTable)->characterClasses = NULL; + (*forwardTable)->ruleNames = NULL; + } + if (backwardTable) { + (*backwardTable)->emphClassNames[0] = NULL; + (*backwardTable)->characterClasses = NULL; + (*backwardTable)->ruleNames = NULL; } /* Compile things that are necessary for the proper operation of @@ -4990,10 +5260,11 @@ /* TODO: These definitions seem to be necessary for proper functioning of liblouisutdml. Find a way to satisfy those requirements without hard coding some characters in every table notably behind the user's back */ - compileString("space \\xffff 123456789abcdef LOU_ENDSEGMENT", translationTable, - displayTable); + compileString("space \\xffff 123456789abcdef LOU_ENDSEGMENT", forwardTable, + backwardTable, displayTable); - if (displayTable && translationTable && strcmp(tableList, displayTableList) == 0) { + if (displayTable && (forwardTable || backwardTable) && + strcmp(tableList, displayTableList) == 0) { /* Compile the display and translation tables in one go */ /* Compile all subtables in the list */ @@ -5002,7 +5273,8 @@ goto cleanup; } for (subTable = tableFiles; *subTable; subTable++) - if (!compileFile(*subTable, translationTable, displayTable)) goto cleanup; + if (!compileFile(*subTable, forwardTable, backwardTable, displayTable)) + goto cleanup; } else { /* Compile the display and translation tables separately */ @@ -5012,17 +5284,18 @@ goto cleanup; } for (subTable = tableFiles; *subTable; subTable++) - if (!compileFile(*subTable, NULL, displayTable)) goto cleanup; + if (!compileFile(*subTable, NULL, NULL, displayTable)) goto cleanup; lou_freeTableFiles(tableFiles); tableFiles = NULL; } - if (translationTable) { + if (forwardTable || backwardTable) { if (!(tableFiles = _lou_resolveTable(tableList, NULL))) { errorCount++; goto cleanup; } for (subTable = tableFiles; *subTable; subTable++) - if (!compileFile(*subTable, translationTable, NULL)) goto cleanup; + if (!compileFile(*subTable, forwardTable, backwardTable, NULL)) + goto cleanup; } } @@ -5032,13 +5305,18 @@ if (warningCount) _lou_logMessage(LOU_LOG_WARN, "%s: %d warnings issued", tableList, warningCount); if (!errorCount) { - if (translationTable) setDefaults(*translationTable); + if (forwardTable) setDefaults(*forwardTable); + if (backwardTable) setDefaults(*backwardTable); return 1; } else { _lou_logMessage(LOU_LOG_ERROR, "%d errors found.", errorCount); - if (translationTable) { - if (*translationTable) freeTranslationTable(*translationTable); - *translationTable = NULL; + if (forwardTable) { + if (*forwardTable) freeTranslationTable(*forwardTable); + *forwardTable = NULL; + } + if (backwardTable) { + if (*backwardTable) freeTranslationTable(*backwardTable); + *backwardTable = NULL; } if (displayTable) { if (*displayTable) freeDisplayTable(*displayTable); @@ -5053,7 +5331,7 @@ lou_getEmphClasses(const char *tableList) { const char *names[MAX_EMPH_CLASSES + 1]; unsigned int count = 0; - const TranslationTableHeader *table = _lou_getTranslationTable(tableList); + const TranslationTableHeader *table = _lou_getForwardTranslationTable(tableList); if (!table) return NULL; while (count < MAX_EMPH_CLASSES) { @@ -5081,35 +5359,52 @@ void getTable(const char *tableList, const char *displayTableList, - TranslationTableHeader **translationTable, DisplayTableHeader **displayTable); + TranslationTableHeader **forwardTable, TranslationTableHeader **backwardTable, + DisplayTableHeader **displayTable); void EXPORT_CALL _lou_getTable(const char *tableList, const char *displayTableList, - const TranslationTableHeader **translationTable, + const TranslationTableHeader **forwardTable, + const TranslationTableHeader **backwardTable, const DisplayTableHeader **displayTable) { - TranslationTableHeader *newTable = NULL; + TranslationTableHeader *newForwardTable = NULL; + TranslationTableHeader *newBackwardTable = NULL; DisplayTableHeader *newDisplayTable = NULL; - getTable(tableList, displayTableList, &newTable, &newDisplayTable); - if (newTable) - if (!finalizeTable(newTable)) newTable = NULL; - *translationTable = newTable; + getTable(tableList, displayTableList, forwardTable ? &newForwardTable : NULL, + backwardTable ? &newBackwardTable : NULL, &newDisplayTable); + if (newForwardTable) + if (!finalizeTable(newForwardTable)) newForwardTable = NULL; + if (newBackwardTable) + if (!finalizeTable(newBackwardTable)) newBackwardTable = NULL; + if (forwardTable) *forwardTable = newForwardTable; + if (backwardTable) *backwardTable = newBackwardTable; *displayTable = newDisplayTable; } /* Checks and loads tableList. */ const void *EXPORT_CALL lou_getTable(const char *tableList) { - const TranslationTableHeader *table = NULL; + const TranslationTableHeader *forwardTable = NULL; + const TranslationTableHeader *backwardTable = NULL; const DisplayTableHeader *displayTable = NULL; - _lou_getTable(tableList, tableList, &table, &displayTable); - if (!table || !displayTable) return NULL; + _lou_getTable(tableList, tableList, &forwardTable, &backwardTable, &displayTable); + if (!forwardTable || !backwardTable || !displayTable) return NULL; + return forwardTable; +} + +const TranslationTableHeader *EXPORT_CALL +_lou_getForwardTranslationTable(const char *tableList) { + TranslationTableHeader *table = NULL; + getTable(tableList, NULL, &table, NULL, NULL); + if (table) + if (!finalizeTable(table)) table = NULL; return table; } const TranslationTableHeader *EXPORT_CALL -_lou_getTranslationTable(const char *tableList) { +_lou_getBackwardTranslationTable(const char *tableList) { TranslationTableHeader *table = NULL; - getTable(tableList, NULL, &table, NULL); + getTable(tableList, NULL, NULL, &table, NULL); if (table) if (!finalizeTable(table)) table = NULL; return table; @@ -5118,23 +5413,24 @@ const DisplayTableHeader *EXPORT_CALL _lou_getDisplayTable(const char *tableList) { DisplayTableHeader *table = NULL; - getTable(NULL, tableList, NULL, &table); + getTable(NULL, tableList, NULL, NULL, &table); return table; } void getTable(const char *translationTableList, const char *displayTableList, - TranslationTableHeader **translationTable, DisplayTableHeader **displayTable) { + TranslationTableHeader **forwardTable, TranslationTableHeader **backwardTable, + DisplayTableHeader **displayTable) { /* Keep track of which tables have already been compiled */ int translationTableListLen, displayTableListLen = 0; if (translationTableList == NULL || *translationTableList == 0) - translationTable = NULL; + forwardTable = backwardTable = NULL; if (displayTableList == NULL || *displayTableList == 0) displayTable = NULL; /* See if translation table has already been compiled */ - if (translationTable) { + if (forwardTable) { translationTableListLen = (int)strlen(translationTableList); - *translationTable = NULL; - TranslationTableChainEntry *currentEntry = translationTableChain; + *forwardTable = NULL; + TranslationTableChainEntry *currentEntry = forwardTranslationTableChain; TranslationTableChainEntry *prevEntry = NULL; while (currentEntry != NULL) { if (translationTableListLen == currentEntry->tableListLength && @@ -5143,10 +5439,32 @@ /* Move the table to the top of the table chain. */ if (prevEntry != NULL) { prevEntry->next = currentEntry->next; - currentEntry->next = translationTableChain; - translationTableChain = currentEntry; + currentEntry->next = forwardTranslationTableChain; + forwardTranslationTableChain = currentEntry; } - *translationTable = currentEntry->table; + *forwardTable = currentEntry->table; + break; + } + prevEntry = currentEntry; + currentEntry = currentEntry->next; + } + } + if (backwardTable) { + translationTableListLen = (int)strlen(translationTableList); + *backwardTable = NULL; + TranslationTableChainEntry *currentEntry = backwardTranslationTableChain; + TranslationTableChainEntry *prevEntry = NULL; + while (currentEntry != NULL) { + if (translationTableListLen == currentEntry->tableListLength && + (memcmp(¤tEntry->tableList[0], translationTableList, + translationTableListLen)) == 0) { + /* Move the table to the top of the table chain. */ + if (prevEntry != NULL) { + prevEntry->next = currentEntry->next; + currentEntry->next = backwardTranslationTableChain; + backwardTranslationTableChain = currentEntry; + } + *backwardTable = currentEntry->table; break; } prevEntry = currentEntry; @@ -5176,27 +5494,42 @@ currentEntry = currentEntry->next; } } - if ((translationTable && *translationTable == NULL) || + if ((forwardTable && *forwardTable == NULL) || + (backwardTable && *backwardTable == NULL) || (displayTable && *displayTable == NULL)) { - TranslationTableHeader *newTranslationTable = NULL; + TranslationTableHeader *newForwardTable = NULL; + TranslationTableHeader *newBackwardTable = NULL; DisplayTableHeader *newDisplayTable = NULL; if (compileTable(translationTableList, displayTableList, - (translationTable && *translationTable == NULL) ? &newTranslationTable - : NULL, + (forwardTable && *forwardTable == NULL) ? &newForwardTable : NULL, + (backwardTable && *backwardTable == NULL) ? &newBackwardTable : NULL, (displayTable && *displayTable == NULL) ? &newDisplayTable : NULL)) { /* Add a new entry to the top of the table chain. */ - if (newTranslationTable != NULL) { + if (newForwardTable != NULL) { int entrySize = sizeof(TranslationTableChainEntry) + translationTableListLen; TranslationTableChainEntry *newEntry = malloc(entrySize); if (!newEntry) _lou_outOfMemory(); - newEntry->next = translationTableChain; - newEntry->table = newTranslationTable; + newEntry->next = forwardTranslationTableChain; + newEntry->table = newForwardTable; newEntry->tableListLength = translationTableListLen; memcpy(&newEntry->tableList[0], translationTableList, translationTableListLen); - translationTableChain = newEntry; - *translationTable = newTranslationTable; + forwardTranslationTableChain = newEntry; + *forwardTable = newForwardTable; + } + if (newBackwardTable != NULL) { + int entrySize = + sizeof(TranslationTableChainEntry) + translationTableListLen; + TranslationTableChainEntry *newEntry = malloc(entrySize); + if (!newEntry) _lou_outOfMemory(); + newEntry->next = backwardTranslationTableChain; + newEntry->table = newBackwardTable; + newEntry->tableListLength = translationTableListLen; + memcpy(&newEntry->tableList[0], translationTableList, + translationTableListLen); + backwardTranslationTableChain = newEntry; + *backwardTable = newBackwardTable; } if (newDisplayTable != NULL) { int entrySize = sizeof(DisplayTableChainEntry) + displayTableListLen; @@ -5225,7 +5558,7 @@ formtype EXPORT_CALL lou_getTypeformForEmphClass(const char *tableList, const char *emphClass) { - const TranslationTableHeader *table = _lou_getTranslationTable(tableList); + const TranslationTableHeader *table = _lou_getForwardTranslationTable(tableList); if (!table) return 0; for (int i = 0; i < MAX_EMPH_CLASSES && table->emphClassNames[i]; i++) if (strcmp(emphClass, table->emphClassNames[i]) == 0) return italic << i; @@ -5345,8 +5678,8 @@ void EXPORT_CALL lou_free(void) { lou_logEnd(); - if (translationTableChain != NULL) { - TranslationTableChainEntry *currentEntry = translationTableChain; + if (forwardTranslationTableChain != NULL) { + TranslationTableChainEntry *currentEntry = forwardTranslationTableChain; TranslationTableChainEntry *previousEntry; while (currentEntry) { freeTranslationTable(currentEntry->table); @@ -5354,7 +5687,18 @@ currentEntry = currentEntry->next; free(previousEntry); } - translationTableChain = NULL; + forwardTranslationTableChain = NULL; + } + if (backwardTranslationTableChain != NULL) { + TranslationTableChainEntry *currentEntry = backwardTranslationTableChain; + TranslationTableChainEntry *previousEntry; + while (currentEntry) { + freeTranslationTable(currentEntry->table); + previousEntry = currentEntry; + currentEntry = currentEntry->next; + free(previousEntry); + } + backwardTranslationTableChain = NULL; } if (displayTableChain != NULL) { DisplayTableChainEntry *currentEntry = displayTableChain; @@ -5411,26 +5755,28 @@ int EXPORT_CALL lou_compileString(const char *tableList, const char *inString) { - TranslationTableHeader *table; + TranslationTableHeader *forwardTable; + TranslationTableHeader *backwardTable; DisplayTableHeader *displayTable; - getTable(tableList, tableList, &table, &displayTable); - if (!table) return 0; - if (!compileString(inString, &table, &displayTable)) return 0; + getTable(tableList, tableList, &forwardTable, &backwardTable, &displayTable); + if (!forwardTable || !backwardTable) return 0; + if (!compileString(inString, &forwardTable, &backwardTable, &displayTable)) return 0; return 1; } int EXPORT_CALL _lou_compileTranslationRule(const char *tableList, const char *inString) { - TranslationTableHeader *table; - getTable(tableList, NULL, &table, NULL); - return compileString(inString, &table, NULL); + TranslationTableHeader *forwardTable; + TranslationTableHeader *backwardTable; + getTable(tableList, NULL, &forwardTable, &backwardTable, NULL); + return compileString(inString, &forwardTable, &backwardTable, NULL); } int EXPORT_CALL _lou_compileDisplayRule(const char *tableList, const char *inString) { DisplayTableHeader *table; - getTable(NULL, tableList, NULL, &table); - return compileString(inString, NULL, &table); + getTable(NULL, tableList, NULL, NULL, &table); + return compileString(inString, NULL, NULL, &table); } /**
diff --git a/liblouis/internal.h b/liblouis/internal.h index ecec50c..7f1fa0b 100644 --- a/liblouis/internal.h +++ b/liblouis/internal.h
@@ -361,10 +361,9 @@ typedef struct { const char *sourceFile; int sourceLine; - int index; /** sequence number of rule within table */ - TranslationTableOffset charsnext; /** next chars entry */ - TranslationTableOffset dotsnext; /** next dots entry */ - TranslationTableCharacterAttributes after; /** character types which must follow */ + int index; /** sequence number of rule within table */ + TranslationTableOffset next; /** next entry in rules, passRules or otherRules */ + TranslationTableCharacterAttributes after; /** character types which must follow */ TranslationTableCharacterAttributes before; /** character types which must precede */ TranslationTableOffset patterns; /** before and after patterns */ TranslationTableOpcode opcode; /** rule for testing validity of replacement */ @@ -484,11 +483,9 @@ [NOEMPHCHARSSIZE + 1]; TranslationTableOffset characters[HASHNUM]; /** Character definitions */ TranslationTableOffset dots[HASHNUM]; /** Dot definitions */ - TranslationTableOffset forPassRules[MAXPASS + 1]; - TranslationTableOffset backPassRules[MAXPASS + 1]; - TranslationTableOffset forRules[HASHNUM]; /** Chains of forward rules */ - TranslationTableOffset backRules[HASHNUM]; /** Chains of backward rules */ - TranslationTableData ruleArea[1]; /** Space for storing all rules and values */ + TranslationTableOffset passRules[MAXPASS + 1]; + TranslationTableOffset rules[HASHNUM]; /** Chains of forward rules */ + TranslationTableData ruleArea[1]; /** Space for storing all rules and values */ } TranslationTableHeader; typedef enum { @@ -582,11 +579,15 @@ void EXPORT_CALL _lou_getTable(const char *tableList, const char *displayTableList, - const TranslationTableHeader **translationTable, + const TranslationTableHeader **forwardTable, + const TranslationTableHeader **backwardTable, const DisplayTableHeader **displayTable); const TranslationTableHeader *EXPORT_CALL -_lou_getTranslationTable(const char *tableList); +_lou_getForwardTranslationTable(const char *tableList); + +const TranslationTableHeader *EXPORT_CALL +_lou_getBackwardTranslationTable(const char *tableList); const DisplayTableHeader *EXPORT_CALL _lou_getDisplayTable(const char *tableList);
diff --git a/liblouis/lou_backTranslateString.c b/liblouis/lou_backTranslateString.c index c636ff5..0ab2677 100644 --- a/liblouis/lou_backTranslateString.c +++ b/liblouis/lou_backTranslateString.c
@@ -196,7 +196,7 @@ outlen == NULL) return 0; if (displayTableList == NULL) displayTableList = tableList; - _lou_getTable(tableList, displayTableList, &table, &displayTable); + _lou_getTable(tableList, displayTableList, NULL, &table, &displayTable); if (table == NULL) return 0; if (!_lou_isValidMode(mode)) @@ -475,7 +475,7 @@ TranslationFound = 1; if (testRule->opcode == CTO_PostPunc) postpuncFound = 1; if (testRule->opcode == CTO_Hyphen) return 1; - testRuleOffset = testRule->dotsnext; + testRuleOffset = testRule->next; } if (TranslationFound && !postpuncFound) return 0; } @@ -571,7 +571,7 @@ const TranslationTableRule **currentRule, const widechar **passInstructions, int *passIC, PassRuleMatch *match) { TranslationTableOffset ruleOffset; - ruleOffset = table->backPassRules[currentPass]; + ruleOffset = table->passRules[currentPass]; while (ruleOffset) { *currentRule = (TranslationTableRule *)&table->ruleArea[ruleOffset]; @@ -602,7 +602,7 @@ return 1; NEXT_RULE: - ruleOffset = (*currentRule)->dotsnext; + ruleOffset = (*currentRule)->next; } return 0; @@ -635,7 +635,7 @@ makeHash = (unsigned long int)dots->value << 8; makeHash += (unsigned long int)(getDots(input->chars[pos + 1], table))->value; makeHash %= HASHNUM; - ruleOffset = table->backRules[makeHash]; + ruleOffset = table->rules[makeHash]; break; case 1: if (!(length >= 1)) break; @@ -850,7 +850,7 @@ } } } /* Done with checking this rule */ - ruleOffset = (*currentRule)->dotsnext; + ruleOffset = (*currentRule)->next; } } } @@ -1031,7 +1031,7 @@ character2 = getChar(input->chars[pos + 1], table); makeHash += (unsigned long int)toLowercase(table, character2); makeHash %= HASHNUM; - ruleOffset = table->backRules[makeHash]; + ruleOffset = table->rules[makeHash]; break; case 1: if (!(length >= 1)) break; @@ -1060,7 +1060,7 @@ break; } } - ruleOffset = currentRule->dotsnext; + ruleOffset = currentRule->next; } tryThis++; }
diff --git a/liblouis/lou_translateString.c b/liblouis/lou_translateString.c index 9f49c8e..07bf14e 100644 --- a/liblouis/lou_translateString.c +++ b/liblouis/lou_translateString.c
@@ -214,7 +214,7 @@ const TranslationTableRule *save_transRule = *transRule; TranslationTableOpcode save_transOpcode = *transOpcode; TranslationTableOffset ruleOffset; - ruleOffset = table->forPassRules[currentPass]; + ruleOffset = table->passRules[currentPass]; *transCharslen = 0; while (ruleOffset) { *transRule = (TranslationTableRule *)&table->ruleArea[ruleOffset]; @@ -222,7 +222,7 @@ if (passDoTest(table, pos, input, *transOpcode, *transRule, passCharDots, passInstructions, passIC, match, groupingRule, groupingOp)) return 1; - ruleOffset = (*transRule)->charsnext; + ruleOffset = (*transRule)->next; } *transCharslen = save_transCharslen; *transRule = save_transRule; @@ -292,8 +292,8 @@ switch (tryThis) { case 0: if (!(length >= 2)) break; - ruleOffset = table->forRules[_lou_stringHash( - &input->chars[pos], 1, table)]; + ruleOffset = + table->rules[_lou_stringHash(&input->chars[pos], 1, table)]; break; case 1: if (!(length >= 1)) break; @@ -321,7 +321,7 @@ break; } } - ruleOffset = transRule->charsnext; + ruleOffset = transRule->next; } tryThis++; } @@ -1194,7 +1194,7 @@ _lou_logMessage(LOU_LOG_ERROR, "Invalid mode parameter: %d", mode); if (displayTableList == NULL) displayTableList = tableList; - _lou_getTable(tableList, displayTableList, &table, &displayTable); + _lou_getTable(tableList, displayTableList, &table, NULL, &displayTable); if (table == NULL || *inlen < 0 || *outlen < 0) return 0; k = 0; while (k < *inlen && inbufx[k]) k++; @@ -1810,7 +1810,7 @@ switch (tryThis) { case 0: if (!(length >= 2)) break; - ruleOffset = table->forRules[_lou_stringHash(&input->chars[p], 1, table)]; + ruleOffset = table->rules[_lou_stringHash(&input->chars[p], 1, table)]; break; case 1: if (!(length >= 1)) break; @@ -1831,7 +1831,7 @@ if (tryThis == 1 || k == testRule->charslen) { if (testRule->opcode == CTO_CompBrl) return 0; } - ruleOffset = testRule->charsnext; + ruleOffset = testRule->next; } } } @@ -1984,7 +1984,7 @@ switch (tryThis) { case 0: if (!(length >= 2)) break; - ruleOffset = table->forRules[_lou_stringHash(&input->chars[pos], 1, table)]; + ruleOffset = table->rules[_lou_stringHash(&input->chars[pos], 1, table)]; break; case 1: if (!(length >= 1)) break; @@ -2284,7 +2284,7 @@ } } /* Done with checking this rule */ - ruleOffset = (*transRule)->charsnext; + ruleOffset = (*transRule)->next; } } } @@ -2317,7 +2317,7 @@ dots[k] = r->charsdots[1]; break; } - offset = r->charsnext; + offset = r->next; } if (!dots[k]) dots[k] = _lou_charToFallbackDots(text[k]); } @@ -2478,8 +2478,7 @@ case 0: if (!(length >= 2)) break; // memory overflow when pos == input->length - 1 - ruleOffset = - table->forRules[_lou_stringHash(&input->chars[pos], 1, table)]; + ruleOffset = table->rules[_lou_stringHash(&input->chars[pos], 1, table)]; break; case 1: if (!(length >= 1)) break; @@ -2504,7 +2503,7 @@ break; } } - ruleOffset = transRule->charsnext; + ruleOffset = transRule->next; } tryThis++; } @@ -3689,7 +3688,7 @@ d = r->charsdots[1]; break; } - offset = r->charsnext; + offset = r->next; } if (!for_updatePositions(&d, 1, 1, 0, pos, input, output, posMapping, cursorPosition, cursorStatus)) @@ -4044,7 +4043,7 @@ while (offset) { rule = (TranslationTableRule *)&table->ruleArea[offset]; if (rule->opcode == CTO_Hyphen) return 1; - offset = rule->charsnext; + offset = rule->next; } return 0; }
diff --git a/liblouis/maketable.c b/liblouis/maketable.c index 51b2049..27d1e12 100644 --- a/liblouis/maketable.c +++ b/liblouis/maketable.c
@@ -30,7 +30,7 @@ extern void loadTable(const char *tableList) { - _lou_getTable(tableList, tableList, &table, &displayTable); + _lou_getTable(tableList, tableList, &table, NULL, &displayTable); } extern int @@ -193,7 +193,7 @@ switch (hash_len) { case 2: if (text_len < 2) break; - offset = table->forRules[_lou_stringHash(text, 1, table)]; + offset = table->rules[_lou_stringHash(text, 1, table)]; break; case 1: offset = table->characters[_lou_charHash(text[0])]; @@ -329,7 +329,7 @@ return 1; next_rule: - offset = rule->charsnext; + offset = rule->next; } } @@ -419,7 +419,7 @@ switch (hash_len) { case 2: if (text_len - n < 2) break; - offset = table->forRules[_lou_stringHash(&text[n], 1, table)]; + offset = table->rules[_lou_stringHash(&text[n], 1, table)]; break; case 1: offset = table->characters[_lou_charHash(text[n])]; @@ -456,7 +456,7 @@ rules[m++] = rule; if (m == rules_len) goto finish; next_rule: - offset = rule->charsnext; + offset = rule->next; } } n++;
diff --git a/tools/lou_checkyaml.c b/tools/lou_checkyaml.c index d055510..0983d4f 100644 --- a/tools/lou_checkyaml.c +++ b/tools/lou_checkyaml.c
@@ -302,7 +302,8 @@ v = read_table_value(parser, start_event->start_mark.line + 1, 0); if (v->content) compile_inline_table(v); - else if (!_lou_getTranslationTable(v->name)) + else if (!_lou_getForwardTranslationTable(v->name) || + !_lou_getBackwardTranslationTable(v->name)) error_at_line(EXIT_FAILURE, 0, file_name, start_event->start_mark.line + 1, "Table %s not valid", v->name); free(emph_classes);
diff --git a/tools/lou_debug.c b/tools/lou_debug.c index 36c2050..4730b9f 100644 --- a/tools/lou_debug.c +++ b/tools/lou_debug.c
@@ -76,7 +76,8 @@ #define BUFSIZE 256 -static const TranslationTableHeader *table; +static const TranslationTableHeader *forwardTable; +static const TranslationTableHeader *backwardTable; static const DisplayTableHeader *displayTable; static char inputBuffer[BUFSIZE]; @@ -151,18 +152,15 @@ printf("attr=%s, ", _lou_showAttributes(thisChar->attributes)); nextRule = thisChar->otherRules; while (nextRule) { - thisRule = (TranslationTableRule *)&table->ruleArea[nextRule]; + thisRule = (TranslationTableRule *)&forwardTable->ruleArea[nextRule]; if (nextRule == thisChar->definitionRule) printf("definition "); printRule(thisRule, mode); printf("\n"); - if (mode == 0) - nextRule = thisRule->charsnext; - else - nextRule = thisRule->dotsnext; + nextRule = thisRule->next; } if (mode == 0 && thisChar->compRule) { TranslationTableRule *compRule = - (TranslationTableRule *)&table->ruleArea[thisChar->compRule]; + (TranslationTableRule *)&forwardTable->ruleArea[thisChar->compRule]; printf("comp6 "); printRule(compRule, 0); printf("\n"); @@ -181,11 +179,11 @@ else k = startHash; for (; k < HASHNUM; k++) - if (table->characters[k]) { + if (forwardTable->characters[k]) { printf("Hash=%d\n", k); - nextChar = table->characters[k]; + nextChar = forwardTable->characters[k]; while (nextChar) { - thisChar = (TranslationTableCharacter *)&table->ruleArea[nextChar]; + thisChar = (TranslationTableCharacter *)&forwardTable->ruleArea[nextChar]; printCharacter(thisChar, 0); printf("=> "); getInput(); @@ -208,11 +206,11 @@ else k = startHash; for (; k < HASHNUM; k++) - if (table->dots[k]) { + if (forwardTable->dots[k]) { printf("Hash=%d\n", k); - nextDots = table->dots[k]; + nextDots = forwardTable->dots[k]; while (nextDots) { - thisDots = (TranslationTableCharacter *)&table->ruleArea[nextDots]; + thisDots = (TranslationTableCharacter *)&forwardTable->ruleArea[nextDots]; printCharacter(thisDots, 1); printf("=> "); getInput(); @@ -235,17 +233,17 @@ else k = startHash; for (; k < HASHNUM; k++) - if (table->forRules[k]) { + if (forwardTable->rules[k]) { printf("Hash=%d\n", k); - nextRule = table->forRules[k]; + nextRule = forwardTable->rules[k]; while (nextRule) { - thisRule = (TranslationTableRule *)&table->ruleArea[nextRule]; + thisRule = (TranslationTableRule *)&forwardTable->ruleArea[nextRule]; printRule(thisRule, 0); printf("=> "); getInput(); if (*inputBuffer == 'h') break; if (*inputBuffer == 'e') return 1; - nextRule = thisRule->charsnext; + nextRule = thisRule->next; } } return 1; @@ -262,17 +260,17 @@ else k = startHash; for (; k < HASHNUM; k++) - if (table->backRules[k]) { + if (backwardTable->rules[k]) { printf("Hash=%d\n", k); - nextRule = table->backRules[k]; + nextRule = backwardTable->rules[k]; while (nextRule) { - thisRule = (TranslationTableRule *)&table->ruleArea[nextRule]; + thisRule = (TranslationTableRule *)&backwardTable->ruleArea[nextRule]; printRule(thisRule, 1); printf("=> "); getInput(); if (*inputBuffer == 'h') break; if (*inputBuffer == 'e') return 1; - nextRule = thisRule->dotsnext; + nextRule = thisRule->next; } } return 1; @@ -282,7 +280,7 @@ print_brailleIndicator(TranslationTableOffset offset, const char *opcode) { TranslationTableRule *thisRule; if (!offset) return 0; - thisRule = (TranslationTableRule *)&table->ruleArea[offset]; + thisRule = (TranslationTableRule *)&forwardTable->ruleArea[offset]; printf("%s %s\n", opcode, _lou_showDots(&thisRule->charsdots[0], thisRule->dotslen)); return 1; } @@ -308,25 +306,25 @@ for (EmphCodeOffset offset = 0; capsNames[offset]; offset++) { print_brailleIndicator( - table->emphRules[MAX_EMPH_CLASSES][offset], capsNames[offset]); + forwardTable->emphRules[MAX_EMPH_CLASSES][offset], capsNames[offset]); } print_phraseLength( - table->emphRules[MAX_EMPH_CLASSES][lenPhraseOffset], "lencapsphrase"); - print_brailleIndicator(table->letterSign, "letsign"); - print_brailleIndicator(table->numberSign, "numsign"); - print_brailleIndicator(table->noNumberSign, "nonumsign"); - print_brailleIndicator(table->noContractSign, "nocontractsign"); + forwardTable->emphRules[MAX_EMPH_CLASSES][lenPhraseOffset], "lencapsphrase"); + print_brailleIndicator(forwardTable->letterSign, "letsign"); + print_brailleIndicator(forwardTable->numberSign, "numsign"); + print_brailleIndicator(forwardTable->noNumberSign, "nonumsign"); + print_brailleIndicator(forwardTable->noContractSign, "nocontractsign"); - for (int i = 0; i < MAX_EMPH_CLASSES && table->emphClassNames[i]; i++) { + for (int i = 0; i < MAX_EMPH_CLASSES && forwardTable->emphClassNames[i]; i++) { for (EmphCodeOffset offset = 0; emphNames[offset]; offset++) { - snprintf(name, BUFSIZE, emphNames[offset], table->emphClasses[i]); - print_brailleIndicator(table->emphRules[i][offset], name); + snprintf(name, BUFSIZE, emphNames[offset], forwardTable->emphClasses[i]); + print_brailleIndicator(forwardTable->emphRules[i][offset], name); } - snprintf(name, BUFSIZE, "lenemphphrase %s", table->emphClasses[i]); - print_phraseLength(table->emphRules[i][lenPhraseOffset], name); + snprintf(name, BUFSIZE, "lenemphphrase %s", forwardTable->emphClasses[i]); + print_phraseLength(forwardTable->emphRules[i][lenPhraseOffset], name); } - print_brailleIndicator(table->begComp, "begcomp"); - print_brailleIndicator(table->endComp, "endcomp"); + print_brailleIndicator(forwardTable->begComp, "begcomp"); + print_brailleIndicator(forwardTable->endComp, "endcomp"); return 1; } @@ -338,18 +336,21 @@ static int show_misc(void) { - printf("Table size: %u\n", table->tableSize); - printf("Bytes used: %u\n", table->bytesUsed); - printf("Number of passes: %d\n", table->numPasses); - printf("'correct' opcodes: %s\n", pickYN(table->corrections)); - printf("'syllable' opcodes: %s\n", pickYN(table->syllables)); - printf("'capsnocont' opcode: %s\n", pickYN(table->capsNoCont)); - printf("Hyphenation table: %s\n", pickYN(table->hyphenStatesArray)); + printf("Table size: %u\n", forwardTable->tableSize); + printf("Bytes used: %u\n", forwardTable->bytesUsed); + printf("Number of passes: %d\n", forwardTable->numPasses); + printf("'correct' opcodes: %s\n", pickYN(forwardTable->corrections)); + printf("'syllable' opcodes: %s\n", pickYN(forwardTable->syllables)); + printf("'capsnocont' opcode: %s\n", pickYN(forwardTable->capsNoCont)); + printf("Hyphenation table: %s\n", pickYN(forwardTable->hyphenStatesArray)); printf("noletsignbefore %s\n", - print_chars(&table->noLetsignBefore[0], table->noLetsignBeforeCount)); - printf("noletsign %s\n", print_chars(&table->noLetsign[0], table->noLetsignCount)); + print_chars(&forwardTable->noLetsignBefore[0], + forwardTable->noLetsignBeforeCount)); + printf("noletsign %s\n", + print_chars(&forwardTable->noLetsign[0], forwardTable->noLetsignCount)); printf("noletsignafter %s\n", - print_chars(&table->noLetsignAfter[0], table->noLetsignAfterCount)); + print_chars( + &forwardTable->noLetsignAfter[0], forwardTable->noLetsignAfterCount)); return 1; } @@ -441,7 +442,7 @@ getInput(); if (!_lou_extParseChars(inputBuffer, parsed)) break; startHash = _lou_charHash(*parsed); - if (table->characters[startHash] == 0) { + if (forwardTable->characters[startHash] == 0) { printf("Character not in table.\n"); break; } @@ -452,7 +453,7 @@ getInput(); if (!_lou_extParseDots(inputBuffer, parsed)) break; startHash = _lou_charHash(*parsed); - if (table->dots[startHash] == 0) { + if (forwardTable->dots[startHash] == 0) { printf("Dot pattern not in table.\n"); break; } @@ -485,7 +486,7 @@ getInput(); if (!_lou_extParseChars(inputBuffer, parsed)) break; startHash = _lou_stringHash(parsed, 0, NULL); - if (table->forRules[startHash] == 0) { + if (forwardTable->rules[startHash] == 0) { printf("Character string not in table.\n"); break; } @@ -496,7 +497,7 @@ getInput(); if (!_lou_extParseDots(inputBuffer, parsed)) break; startHash = _lou_stringHash(parsed, 0, NULL); - if (table->backRules[startHash] == 0) { + if (backwardTable->rules[startHash] == 0) { printf("Dot pattern not in table.\n"); break; } @@ -608,8 +609,9 @@ exit(EXIT_FAILURE); } - _lou_getTable(argv[optind], argv[optind], &table, &displayTable); - if (!table) { + _lou_getTable( + argv[optind], argv[optind], &forwardTable, &backwardTable, &displayTable); + if (!forwardTable || !backwardTable || !displayTable) { lou_free(); exit(EXIT_FAILURE); }
diff --git a/tools/lou_trace.c b/tools/lou_trace.c index 0052b97..2568aed 100644 --- a/tools/lou_trace.c +++ b/tools/lou_trace.c
@@ -293,7 +293,7 @@ inlen = get_wide_input(inbuf); outlen = BUFSIZE; ruleslen = RULESSIZE; - _lou_getTable(table, table, &translationTable, &displayTable); + _lou_getTable(table, table, &translationTable, NULL, &displayTable); if (backward_translation) { if (!_lou_backTranslate(table, table, inbuf, &inlen, outbuf, &outlen, NULL, NULL, NULL, NULL, NULL, mode, rules, &ruleslen))