Подтвердить что ты не робот

Перевод исходного кода на иностранный язык

У меня работает образовательный сайт, который учит программированию детям (12-15 лет).

Поскольку они не все говорят по-английски в источнике кода решений, мы используем имена переменных и функций во Франции. Однако мы планируем перевести контент на другие языки (немецкий, испанский, английский). Для этого я хотел бы как можно быстрее перевести исходный код. У нас в основном есть код C/С++.

Решение, которое я планирую использовать:

  • извлекать все имена переменных/функций из исходного кода, их позицию в файле (где они объявлены, используются, вызывают...)
  • удалить все языковые ключевые слова и библиотечные функции.
  • попросите переводчика предоставить переводы для остальных имен
  • заменить имена в файле

Есть ли какой-нибудь открытый код/​​проект с открытым исходным кодом, который может это сделать? (Для точек 1,2 и 4)

Если этого не происходит, самая сложная точка в первом: использование синтаксического анализатора C/С++ для создания синтаксического дерева, а затем извлечение переменных с их позицией, похоже, способ. У вас есть другие идеи?

Спасибо за любые советы.

Изменить: Как отмечено в комментарии, мне также нужно будет позаботиться о комментариях, но их осталось лишь немного: полное решение уже объяснено в текстовом виде, а затем мы показываем код-источник с самообучаемой переменной/функцией имена. Исходный код редко бывает длиннее 30/40 строк, а хорошие имена должны быть понятны без комментариев, если вы уже знаете, что делает код.

Дополнительная информация: для людей, заинтересованных в веб-сайте, является учебной площадкой для международных олимпиад по информатике и C/С++ (по крайней мере, минимальным, необходимым для конкурса на программирование), не так сложно изучить 12 лет.

4b9b3361

Ответ 1

Вам действительно не нужен синтаксический анализатор C/С++, просто простой лексер, который дает вам элементы кода один за другим. Затем вы получаете много {, [, 213, ) и т.д., Которые вы просто игнорируете и записываете в файл результатов. Вы переводите все, что состоит из только букв (кроме ключевых слов), и вы помещаете их в вывод.

Теперь, когда я думаю об этом, это так просто:

bool is_letter(char c)
{
    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
bool is_keyword(string &s)
{
    return s == "if" || s == "else" || s == "void" /* rest of them */;
}
void translateCode(istream &in, ostream &out)
{
    while (!in.eof())
    {
        char c = in.get();
        if (is_letter(c))
        {
            string name = "";
            do
            {
                name += c;
                c = in.get();
            } while (is_letter(c) && !in.eof());
            if (is_keyword(name))
                out << name;
            else
                out << translate(name);
        }
        out << c;  // even if is_letter(c) was true, there is a new c from the
                   // while inside that was read (which was not letter), but
                   // not written, so would be written here.
    }
}

Я написал код в редакторе, поэтому могут быть небольшие ошибки. Скажите мне, если они есть, и я исправлю это.

Изменить: Объяснение:

То, что делает код, это просто прочитать входной символ по символу, выводя любые небуквенные символы, которые он читает (включая пробелы, вкладки и новые строки). Если он видит письмо, он начнет помещать все следующие буквы в одну строку (пока не достигнет другой небукты). Тогда, если строка была ключевым словом, она вывела бы ключевое слово. Если бы это было не так, перевести его и вывести его.

Выход будет иметь тот же формат, что и вход.

Ответ 2

Вы уверены, что для этого требуется полное синтаксическое дерево? Я думаю, что достаточно будет лексического анализа, чтобы найти идентификаторы, что намного проще. Затем исключайте ключевые слова и идентификаторы, которые также отображаются в заголовочных файлах.

В принципе возможно, что вы хотите, чтобы разные переменные с одним и тем же английским именем были переведены на разные слова на французском/немецком языке, но для образовательного использования риск возникновения этого явления, вероятно, достаточно мал, чтобы сначала игнорировать. Вы можете обойти проблему, написав исходные источники с некоторыми двусмысленными квази-венгерскими префиксами, а затем удалите их с тем же механизмом перевода для отображения англоязычным конечным пользователям.

Не забудьте, чтобы переводчики увидели имя, которое они переводили, с полным контекстом, прежде чем выбрать перевод.

Ответ 3

Я действительно думаю, что вы можете использовать clang (libclang), чтобы анализировать ваши источники и делать то, что вы хотите (см. здесь для получения дополнительной информации), хорошей новостью является то, что у них есть привязки к python, что облегчит вашу жизнь, если вы хотите получить доступ к службе перевода или что-то в этом роде.

Ответ 4

Я не думаю, что замена идентификаторов в коде - хорошая идея.

Во-первых, вы не получите достойных переводов. Очень важный момент заключается в том, что перевод (особенно автоматический или довольно тупой перевод) теряет и искажает информацию. На самом деле у вас может быть что-то хуже, чем оригинал.

Во-вторых, если код предназначен для компиляции снова, компилятор, возможно, не сможет скомпилировать код, содержащий неанглийские буквы в переведенных идентификаторах.

В-третьих, если вы заменяете идентификаторы чем-то другим, вам нужно убедиться, что вы не заменяете 2 или более разных идентификатора одним и тем же словом. Это либо сделает код не компилируемым, либо разрушит его логику.

В-четвертых, вы должны убедиться, что вы не переводите зарезервированные слова и идентификаторы из стандартной библиотеки языка. Перевод этих данных сделает код не компилируемым и нечитаемым. Не может быть очень тривиальной задачей различать идентификаторы, определенные программистом, от тех, которые предоставляются языком и его стандартной библиотекой.

Что бы я сделал вместо замены идентификаторов их переводами, предоставляйте переводы как комментарии рядом с ними, например:

void eat/*comer*/(int* food/*comida*/)
{
  if (*food/*comida*/ <= 0)
  {
    printf("nothing to eat!"/*no hay que comer!*/);
    exit/*salir*/(-1);
  }
  (*food/*comida*/)--;
}

Таким образом вы теряете информацию из-за неправильного перевода и не нарушаете код.