Русский
Русский
English
Статистика
Реклама

Трансляторы

Сложности работы с ANTLR пишем грамматику Ruby

04.08.2020 10:19:03 | Автор: admin
image В Ростелеком-Солар мы разрабатываем статический анализатор кода на уязвимости и НДВ, который работает в том числе на деревьях разбора. Для их построения мы пользуемся оптимизированной версией ANTLR4 инструмента для разработки компиляторов, интерпретаторов и трансляторов.

В репозитории можно найти грамматики множества языков программирования. Однако в нем отсутствует грамматика Ruby, которую, по всей видимости, никто так и не реализовал. Есть только грамматика похожего самодельного языка, парсящая лишь простейшие случаи. Это неудивительно, ведь грамматику Ruby сложно реализовать, так как язык обладает нетривиальным синтаксисом. Но она очень пригодилась бы тем, кто, например, захочет написать свой язык и задумается, как это сделать. Или тем, кому нужно решить технические сложности, рассмотренные в нашей статье. Ну что же придется писать новую грамматику, чем прямо здесь и займемся.


В ANTLR предлагается разбивать анализ языка на лексер и парсер.

Лексер занимается тем, что формирует токены на основе заданных последовательностей символов из алфавита языка. Если последовательность символов подходит под определение нескольких токенов, выбирается наидлиннейший, а среди таких первый по приоритету (который задается порядком записи).

Парсер формирует предложения (законченные команды) языка с помощью токенов (также называемых терминальными символами), получаемых из лексера.

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

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

Проблемы лексера


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

Интерполяция


Некоторые строки в Ruby допускают интерполяцию вставку произвольного кода внутрь с помощью синтаксиса #{code}. Например:

a = 3"Hello #{if a%2==1 then "Habr!" else "World!" end}"

Справляться будем с помощью режимов специфичных маленьких лексеров, предназначенных под определенную задачу, вроде нашего парсинга строки:

DoubleQuote: '"' {++nestedStringLevel;}    -> pushMode(InterpolationString);

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

"Kappa #{    buf = ''    [1, 2, 3].each { |x| buf += x.to_s }    buf}"

Для этого заведем стек openedCurlyBracesInsideString. Итого внутри мода имеем токен:

StartInterpolation: '#{' {openedCurlyBracesInsideString.push(0);}    -> pushMode(DEFAULT_MODE);

Теперь же нужно вовремя выйти из обычного режима (DEFAULT_MODE), для этого добавим код в токены:

OpenCurlyBracket:             '{' {    if (nestedStringLevel > 0 && !openedCurlyBracesInsideString.empty()) {        final int buf = openedCurlyBracesInsideString.pop();        openedCurlyBracesInsideString.push(buf + 1);    }};CloseCurlyBracket:            '}' {    if (nestedStringLevel > 0 && openedCurlyBracesInsideString.peek() <= 0) {       popMode();       openedCurlyBracesInsideString.pop();    } else {        if (!openedCurlyBracesInsideString.empty()) {            final int buf = openedCurlyBracesInsideString.pop();            openedCurlyBracesInsideString.push(buf - 1);        }    }};

%-нотации


В Ruby существует вдохновленный Perl дополнительный синтаксис написания строк, массивов строк и символов (который в Ruby не является символом в обычном понимании), регулярных выражений и шелл-команд. Синтаксис таких команд таков: %, следующий за ним опциональный идентификатор типа и символ-разделитель. Например: %w|a b c| массив из трех строк. Однако, также можно использовать в качестве разделителя парные скобки: {} [] () <>. Просто задать все возможные идентификаторы не выйдет тогда, например, последовательность

q = 35%q

будет распознаваться некорректно. Лексер просто съест самую длинную цепочку символов, создав токен %q.

Создав проверку на отсутствие явно невалидного разделителя вроде пробельного символа, цифры и буквы и добавив её в токен в качестве предиката (условие, которое обязано выполняться в определенном месте для продолжения конструирования токена),

StringArrayConstructorwToken: '%w' {canBeDelimiter()}?;

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

StartArrayConstructorNotInterpolated    : StringArrayConstructorwToken ( Brackets {setPairDelimiter();} | ~[(<{[] {setCharDelimiter();} ) {startStringMode(ArrayConstructorw);}fragment Brackets: '(' | '[' | '{' | '<';

где startStringMode utility-функция для переключения режима и поддержки вложенности.

public void startStringMode(final int mode) {    pushMode(mode);    ++nestedStringLevel;}

Контрпример: 5%q|1 парсящийся корректно лишь в контексте парсера, когда известно, что после 5-ти задания строки быть не может.

Можно было бы подумать, что достаточно найти парный разделитель с помощью заглядывания вперед, однако и на такой случай есть пример 5%q|1|1. Откуда становится ясно, что при разделении на лексер и парсер подобный случай распарсить невозможно.

Однако такое случается очень редко, так что сойдет \_()_/. Внутри режима же просто ждем разделитель.

ArraywWhitespace: WhitespaceAll                           -> skip;ArraywText:       ({!isDelimiter()}? ArraywTextFragment)+ -> type(StringPart);ArraywEnd:        . {nestedStringLevel--;}                -> type(HereDocEnd), popMode;

где type изменяет тип создаваемых токенов для удобства.

Деление или начало регулярного выражения


Синтаксис регулярного выражения таков /regexp/ (а также вышеупомянутая нотация с процентом). Возникает такая же проблема контекста парсера, как и в предыдущем пункте, для её смягчения создаем проверку

public boolean canBeRegex() {    return isPrevWS && " \t\r\u000B\f\b\n".indexOf((char) _input.LA(1)) == -1 || isPrevNL || isOp || prevNonWsType == StartInterpolation;}

и добавляем в токен

Divide:                       '/' {    if (canBeRegex()) {        startHereDoc(RegExp);    }};

Для пересчета переменных isOp, isPrevNL, isPrevWS также переопределяем emit-функцию итогового создания токена

@Overridepublic void emit(final Token token) {    final String txt = token.getText();    final int type = token.getType();    isPrevNL = type == NL;    isPrevWS = type == WS;    if (!isPrevWS && !isPrevNL && type != SingleLineComment && type != MultiLineComment) {        isOp = OPERATORS.contains(type);        prevNonWsChar = txt.charAt(txt.length() - 1);        prevNonWsType = type;    }    super.emit(token);}

где OPERATORS hashmap всех операторов.

Проблемы парсера


Пробельные символы


Довольно неприятным сюрпризом стало влияние пробелов на парсинг. Обычно они никак не сказываются на грамматике и просто-напросто удаляются из потока с помощью -> skip или перевода в другой канал. Однако ряд языков все же различает некоторые конструкции с их помощью.

Так, например, a+3 и a + 3 не могут быть вызовом функции без скобок, а а +3 может. Поэтому все правила парсера выглядят так (NL newline, WS whitespace):

    | expression WS* op=('+' | '-') (NL | WS)* expression

Для смягчения проблемы, напишем listener , который будет чистить нам дерево разбора от подобного мусора.

public class RemovingTokensListener implements ParseTreeListener {        private List<Integer> unwantedTokens;        ...        @Override        public void visitTerminal(final TerminalNode node) {            if (this.unwantedTokens.contains(node.getSymbol().getType())) {                ((ParserRuleContext) node.getParent().getRuleContext()).removeLastChild();            }        }}

Heredoc Лексер и парсер


Специальный синтаксис задания многострочных строк. Может быть таким

<<STRcontent line 1content line 2STR

или даже таким (интересно, что markdown не распознает синтаксис корректно).

value = 123print <<STR_WITH_INTERPOLATION, <<'STR_WITHOUT_INTERPOLATION'.stripcontent 1 and #{value}STR_WITH_INTERPOLATION     content 2 and #{value}STR_WITHOUT_INTERPOLATION

Проблема заключается в том, что нужно понимать, где заканчивается строка, а также было бы удобно знать, какой контент относится к какой строке. Для этого сначала создадим лист ожидающих парсинга heredoc-ов (парсер в зависимости от контекста и режима может подгружать произвольное число токенов вперед)

public final HeredocsHolder HEREDOCS = new HeredocsHolder();public static final class HereDocEntry {    public final String name;    public final HereDocType type;    public final boolean isInterpolated;    public int partsNumber;    public HereDocEntry(final String name, final HereDocType type, final boolean isInterpolated) {        this.name = name;        this.type = type;        this.isInterpolated = isInterpolated;        this.partsNumber = 0;    }}public static final class HeredocsHolder {    public final List<HereDocEntry> entries;    public int toProcess;    HeredocsHolder() {        this.entries = new ArrayList<>();        this.toProcess = 0;    }}

и будем добавлять их по мере поступления

StartHereDoc    : HereDocToken HereDocName {        heredocIdentifier = getHeredocIdentifier('\'');        setText(getText().trim());        keepHereDoc(HereDoc, false);    }    ;

public void keepHereDoc(final int mode, final boolean isInterpolated) {    HEREDOCS.entries.add(new HereDocEntry(heredocIdentifier, getHereDocType(), isInterpolated));    ++HEREDOCS.toProcess;    isFirstNL = true;}


Далее, увидев конец строки при ожидающих обработки heredoc-ах, вызовем функцию обработки.

NL:                           '\n' {    final int next = _input.LA(1);    if (HEREDOCS.toProcess > 0 && isFirstNL) {        startHereDocRoutine();        isFirstNL = false;        insideHeredoc = true;    }};

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

public void startHereDocRoutine() {    final int stopIdx = HEREDOCS.entries.size() - HEREDOCS.toProcess;    for (int i = HEREDOCS.entries.size() - 1; i >= stopIdx; --i) {        if (HEREDOCS.entries.get(i).isInterpolated) {            pushMode(HereDocInterpolated);        } else {            pushMode(HereDoc);        }    }    nestedStringLevel += HEREDOCS.toProcess;    currentHeredocIt = HEREDOCS.entries.listIterator(HEREDOCS.entries.size() - HEREDOCS.toProcess);    currentHeredoc = currentHeredocIt.next();}

Нужно перезаписать nextToken для выхода из режима и подсчета числа токенов каждого heredoc-а

@Overridepublic Token nextToken(){    final CommonToken token = (CommonToken)super.nextToken();    final int ttype = token.getType();    if (insideHeredoc && ttype == StartInterpolation) {        ++heredocTokensCount;    }    if (_mode == HereDoc || _mode == HereDocInterpolated) {        if (ttype == VarName) {            ++heredocTokensCount;        } else if (ttype == StringPart) {            ++heredocTokensCount;            final String txt = token.getText();            if (CheckHeredocEnd(txt)) {                token.setText(txt.trim());                token.setType(HereDocEnd);                nestedStringLevel--;                popMode();                currentHeredoc.partsNumber = heredocTokensCount;                if (currentHeredocIt.hasNext()) {                    currentHeredoc = currentHeredocIt.next();                }                heredocTokensCount = 0;                --HEREDOCS.toProcess;                if (_mode == DEFAULT_MODE) {                    insideHeredoc = false;                }            }        }    }    return token;}

Теперь займемся парсером.

С помощью @parser::members добавим в парсер: ссылку на лексер, узлы строк, куда будем переносить их контент, число узлов интерполяции (по аналогии с heredocTokensCount лексера), а также стек statement-ов с указанием необходимости обработки.

    private final RubyLexer lexer = (RubyLexer)_input.getTokenSource();    private final List<ParserRuleContext> CONTEXTS = new ArrayList<>();    private final List<Integer> heredocRulesCount = new ArrayList<>();    private final Stack<StatementEntry> statements = new Stack<>();    private static final class StatementEntry {        public boolean needProcess;        public int currentHeredoc;        StatementEntry() {            this.needProcess = false;            this.currentHeredoc = 0;        }    }

Модифицируем непосредственно единицу кода:

statement@init {    statements.push(new StatementEntry());}@after {    if (statements.peek().needProcess) {        processHeredocs($ctx);    }    statements.pop();}    : statementWithoutHeredocTail ({statements.peek().needProcess}? interpolatedStringPart* HereDocEnd {++statements.peek().currentHeredoc;})*    ;

@init код, который исполняется при входе парсера в правило, @after при выходе.

Стек необходим для отнесения heredoc-ов к нужному statement-у, т.к. внутри интерполяции могут быть новые.

Для того, чтобы правильно распознать случаи, где heredoc может быть обычным expression и где строку можно считать токенами подряд, а также сложные кейсы, когда конец строки будет лежать за текущим выражением, пишем такой вот код парсера:

string:...    | StartInterpolatedHereDoc (memberAccess* WS* NL interpolatedStringPart* HereDocEnd)? {        if ($ctx.HereDocEnd() == null) {            CONTEXTS.add($ctx);            heredocRulesCount.add(0);            statements.peek().needProcess = true;        } else {             lexer.HEREDOCS.entries.remove(0);        }    }...

Для самого же подсчета узлов интерполяции модифицируем код правила с контентом строки (+ 2 здесь нужно для подсчета токенов, открывающих и закрывающих интерполяцию)

interpolatedStringPartlocals[int nodesCount = 0]    : StringPart    | VarName    | StartInterpolation (WS* statement {++$nodesCount;})* (WS* rawStatement {++$nodesCount;})? WS* '}' {        final int cur = statements.peek().currentHeredoc;        if (cur < heredocRulesCount.size()) {            heredocRulesCount.set(cur, heredocRulesCount.get(cur) + $nodesCount + 2);        }    }    ;

где locals список локальных переменных (ссылаться на них нужно через $), а пробельные токены не считаются, т.к. удаляются во время построения дерева нашим listener-ом.

Теперь напишем саму функцию processHeredocs. Посчитаем, сколько узлов предстоит забрать

int heredocNodesCount = 0;for (int i = 0; i < CONTEXTS.size(); ++i) {    heredocNodesCount += lexer.HEREDOCS.entries.get(i).partsNumber;    heredocNodesCount += heredocRulesCount.get(i);}

Начиная с какого ребенка, начнем перекидывать контент строк по своим местам

int currentChild = ctx.getChildCount() - heredocNodesCount;

Подвесим контент к соответствующему узлу

for (int i = 0; i < CONTEXTS.size(); ++i) {    final RubyLexer.HereDocEntry entry = lexer.HEREDOCS.entries.remove(0);    final ParserRuleContext currentContext = CONTEXTS.get(i);    final int currentNodesCount = entry.partsNumber + heredocRulesCount.get(i);    for (int j = 0; j < currentNodesCount; ++j, ++currentChild) {        final ParseTree child = ctx.getChild(currentChild);        if (child instanceof TerminalNode) {            ((TerminalNodeImpl) child).setParent(currentContext);            currentContext.addChild((TerminalNodeImpl) child);        } else if (child instanceof ParserRuleContext) {            ((ParserRuleContext) child).setParent(currentContext);            currentContext.addChild((ParserRuleContext) child);        } else {            // parser failed            clear();            return;        }    }}

Очищаем сам узел, контексты heredoc-ов и список числа узлов интерполяции

for (int i = 0; i < heredocNodesCount; ++i) {    ctx.removeLastChild();}clear();

private void clear() {    CONTEXTS.clear();    heredocRulesCount.clear();}

Последним штрихом можно удалить ненужное промежуточное правило для обработки heredoc-ов statementWithoutHeredocTail, переподвешивая детей узла к его предку, с помощью того же listener-а

public class RemovingRulesListener implements ParseTreeListener {    private List<Integer> unwantedRules;    ...    @Override    public void exitEveryRule(final ParserRuleContext ctx) {        if (this.unwantedRules.contains(ctx.getRuleIndex())) {            final ParserRuleContext parentCtx =                    (ParserRuleContext) ctx.getParent().getRuleContext();            parentCtx.children.remove(ctx);            ctx.children.forEach(                    child -> {                        if (child instanceof RuleContext) {                            ((RuleContext) child).setParent(parentCtx);                            parentCtx.addChild((RuleContext) child);                        } else if (child instanceof TerminalNode) {                            ((TerminalNodeImpl) child).setParent(parentCtx);                            parentCtx.addChild((TerminalNodeImpl) child);                        }                    }            );        }    }}

Ambiguity


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

Суть заключается в том, что при входе a +a +a +a... на каждом шаге может быть как обычное сложение, так и вызов функции без аргументов (хотя и в таком случае Ruby требует отсутствия пробела после знака у первого аргумента), отчего по всей видимости возникает экспоненциальный рост хождений по графу предсказаний.

Однако просто-напросто запретить ANTLR пробел после унарного оператора в контексте не выйдет придется вручную переписывать леворекурсивный expression, разрешаемый автоматически для случая без аргументов. Полагаясь на то, что никто не пишет более тридцати слагаемых без причины, данная проблема отпадает.

Заключение


Экспериментально данная грамматика может распарсить 99% файлов.

Так, aws-sdk-ruby, содержащий 3024 ruby-файла, падает лишь на семи, fastlane, содержащий 1028, на 2-x, а Ruby on Rails c 2081, на 19-ти.

Однако все же есть принципиально бОльные моменты вроде heredoc-ов, входящих в expression

option(:sts_regional_endpoints,  default: 'legacy',  doc_type: String,  docstring: <<-DOCS) do |cfg|Passing in 'regional' to enable regional endpoint for STS for all supportedregions (except 'aws-global'), defaults to 'legacy' mode, using global endpointfor legacy regions.  DOCS  resolve_sts_regional_endpoints(cfg)end

или используемых как выражения, любых типов блоков

def test_group_by_with_order_by_virtual_count_attribute    expected = { "SpecialPost" => 1, "StiPost" => 2 }    actual = Post.group(:type).order(:count).limit(2).maximum(:comments_count)    assert_equal expected, actualend if current_adapter?(:PostgreSQLAdapter)

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

Автор: Федор Усов, разработчик Solar appScreener
Подробнее..

Андрей Терехов от Фортрана до Питона

25.11.2020 22:06:19 | Автор: admin


Этой осенью Андрей Терехов завкафедрой системного программирования Матмеха СПбГУ, профессор, доктор физмат наук рассказывал нашим коллегам об истории популярных языков программирования и их проникновении в СССР. Вместе с Андреем Николаевичем мы подготовили на основе его лекции материал о том, как разные языки пересекали железный занавес, как их транслировали на разные архитектуры, как некоторые из них входили в моду. Общие тенденции и личные впечатления для всех, кто хочет составить общее представление об истории вопроса.
Для тех, кто предпочитает смотреть или слушать, видео лекции размещено здесь.

Программирование в кодах


Первая действительно электронная машина называлась ЭНИАК Electronic Numerical Integrator and Computer и была сделана в 1946 году американцами. В основе таких ЭВМ лежит триггер, который в 1918 году изобрел житель Петрограда Михаил Александрович Бонч-Бруевич. В отличие от Попова, он даже права на изобретение успел закрепить. Сама по себе схема была довольно известной: мой отец, военный инженер-электронщик, использовал эти триггеры еще до войны.

Уже в 1949 году советский инженер Сергей Алексеевич Лебедев в Киеве сделал машину МЭСМ. От американцев он отстал всего на три года, хотя Киев был практически полностью разрушен. Лебедеву даже здание дали в местечке Феофания тогда оно еще находилось в 30 км от города где до войны находилась психиатрическая лечебница. Но других зданий тогда просто не было.


Здание в Феофании, сейчас районе, а в 1950-х пригороде Киева, где работал Сергей Лебедев

Для этих первых ЭВМ люди писали в двоичных кодах. Скажем, программа выглядит так: 01 100 101 110. Предположим, 01 код сложения. Тогда здесь написано: сложить слово, которое лежит по адресу 100, со словом, которое лежит по адресу 101, и записать результат по адресу 110. В целом все понятно, но как человек, заставший программирование в кодах, скажу вам, что это жутко неудобно. Да вы и сами наверняка это понимаете.

С 1964-го по 1966 год я учился в 157-й математической школе рядом со Смольным, одной из самых известных в Ленинграде, подчиненной не РОНО, а Академии педагогических наук. Там у нас было два Урала-1 и две девушки-техника, которые не умели на них программировать, но могли эти машины чинить. Мне самому тоже пришлось сначала научиться их ремонтировать, но потом мы на Уралах написали много полезных программ, даже для геологов что-то считали.

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

Мы набивали программы на кинопленке шириной 35 мм, которую склеивали в кольцо, если нужен был цикл. Вводишь программу записываешь карандашиком контрольную сумму. Еще раз вводишь: если контрольные суммы совпали, значит, все правильно. Если не совпали вводишь в третий раз, и так до опупения.

Неудобно было настолько, что люди довольно быстро придумали символические замены. Вместо 01 стало можно написать просто символ +, а вместо адреса a, b или c. Это был язык ассемблера, с помощью очень простого транслятора программу можно было перевести в коды машины. Требовалось два просмотра: в первом составляешь таблицу всех идентификаторов и их адресов, во втором подменяешь идентификаторы на адреса, и всё.

Но все равно можно было складывать яблоки с коровами (эта шутка тогда была очень популярна). Поскольку что такое адрес 101? Что в нем лежит? А черт его знает. А что лежит в адресе 102? Тот же ответ. Народ ругался, потому что ошибок было множество, и отладка программ шла тяжело.

Фортран


Американец Джон Бэкус, который в 1957 году придумал язык Фортран (FORmula TRANslator), произвел настоящую революцию. В IBM, где он работал, вообще много чего придумали, включая, например, перфокарты. Фортран позволял записывать формулу, с него были созданы первые трансляторы, гораздо более сложные, чем транслятор с языка ассемблера. Т. е. люди смогли писать нормальные программы на нормальном алгоритмическом языке.


Джон Бэкус признавался, что главным стимулом в поиске ему служила лень и желание упростить процесс написания программ. На фото Бэкус на обложке Think, корпоративного журнала IBM

Как ни смешно, Фортран до сих пор популярен, особенно у физиков и инженеров, которые считают, что им ничего больше не надо, хотя прошло столько лет. Накоплены тонны стандартных программ огромные библиотеки.

Но, как обычно, не обошлось без существенных ошибок. Самая дорогая случилась более полувека назад. Один инженер написал такую программу:
DО 3 I = 1,4
Это цикл. Операторы до метки 3 надо выполнить при I, равном 1,2, 3, 4. Но американец ошибся и вместо запятой между 1 и 4 поставил точку. В Фортране никакой обязательности описания нет, поэтому ошибку не обнаружили. В результате был сорван космический полет на Венеру.

Еще Ломоносов открыл, что вокруг Венеры очень плотная атмосфера, но поверхность планеты никто не видел. Американцы отправили ракету с важным заданием: она должна была долететь до Венеры, сделать несколько оборотов, а потом поднырнуть под атмосферу и сфотографировать поверхность. Ракета летела три месяца и долетела. Когда поднырнула, створка фотоаппарата не открылась, потому что за ее открытие отвечали именно эти строчки. Так много миллиардов долларов в буквальном смысле улетели в воздух. Скандал был неимоверный, человека, сделавшего ошибку, нашли. 67 млрд даже для богатых американцев потеря ощутимая. Но этот программист не пострадал, т. к. на документах имелись подписи всех возможных начальников. После долгих разбирательств решили, что во всем виноват Фортран: правила определения языка оказались очень неудобны и ненадежны.

В середине 1970-х мы сделали первый транслятор с Алгола 68, и со старых языков переводили на него всех подряд. В частности, перевели 93-й ящик сейчас это Институт радионавигации и точного времени.


В здании Ленинградского научно-исследовательского радиотехнического института Российского Института радионавигации и времени сейчас находится офис банка Россия

Раньше он располагался в огромном желтом здании напротив Смольного, сейчас в нем банк, а институт на окраину города выселили. Тогда мы переводили десятки программ с Фортрана на Алгол 68 и всегда выигрывали в четыре раза. Я думал, что тут какое-то жульничество, потому что выигрывать мы должны были вдвое просто за счет лучшего транслятора. Почему же выигрываем в четыре? Разобрались. Алголу 68 мы людей учили я читал лекции, мой ученик Леха Рохлин вел практику. А на Фортране они писали, как курица лапой.

Один раз звонит мне мой бывший ученик, майор советской армии запаса Андрей Сергеевич Агапов: Андрей, на одной из программ ответ разошелся в 4 раза с фортранным. Поскольку несколько десятков программ прошло хорошо, отвечаю: Плевать, бывает. Он: Нет, это управление радиолокатором, который определяет координаты для стрельбы. Если из-за ошибки в программе ракета полетит не туда, мало никому не покажется. Стал разбираться. Думал, что врет Алгол 68, все-таки новый транслятор. Все проверил не врет. Ассемблерные порождения стал читать нет, не врет. Тогда я стал внимательно читать программу на Фортране. Ничего не нашел. Уже озверел, месяц потратил. Стал читать ассемблерное порождение Фортрана, а оно дурацкое. Нашел! Смотрите.

Было написано:
X = 9.3.
Но Х был двойной точности, а 9.3 короткое число. В результате породились две команды.
LE 0, =E 9.3
STD 0, Х.
На ЕС ЭВМ была такая машина, копия IBM 360 слово 64 разряда. И вот команда LE загружала только в левую половину регистра, а в правой половине оставляла мусор. А команда STD выгружала весь регистр. Поскольку процесс был плохо обусловлен, т. е. малые изменения входных данных сильно влияли на результат, ответ после 11 минут процессорного времени разошелся в четыре раза. Оказывается, надо было написать тут еще шесть нулей:
Х = 9.3000000
Я эту ошибку нашел и запомнил на всю жизнь, хотя это 40 лет назад было.


Есть понятие дружественная система, а есть недружественной. Это типичный пример недружественной системы.

Или более простой пример, над которым все мои студенты страдают.
Х=1/3
Любой нормальный человек думает, что будет 0,33. Фиг вам! Будет ноль. Два целых числа, значит, будет деление нацело. А хотите получить 0,33, поставьте две точки:
Х=1./3.
Достаточно в одном месте, тогда будет правильно. Но опять-таки кто такое заметит?

Aлгол 60


Фортран был признан виновным во всех смертных грехах, и люди стали выдумывать новые языки программирования. Европейцы придумали Алгол 60. Тут тоже некоторое баловство с циферками: придумали его в 1958 году через год после Фортрана. Но он был такой корявый и дурной, что язык стали пересматривать и приняли на конгрессе IFIP (International Federation оf Information Processing) только в 1960-м отсюда название. Но работу продолжили, и в 1964-м вышло пересмотренное сообщение об Алголе 60. Мы по нему и работали 6 лет. Запомните эту цифру, она еще несколько раз встретится. Шесть лет нужно, чтобы довести начальный вариант языка до совершенного.

Первый в СССР транслятор с Алгола 60 был сделан в Центре Королева (это космический институт, ныне НПО Энергия) под руководством Святослава Сергеевича Лаврова, который с 1972 года стал завкафедрой матобеспечения ЭВМ, где я сейчас работаю.


Святослав Лавров, 1987 г. Фото из архива академика Андрея Ершова

Лавров был начальником отдела внешней баллистики именно он рассчитывал траекторию первого спутника, траекторию Гагарина. Он рассказывал, как это выглядело в эпоху до ЭВМ, когда несколько сот женщин целыми днями крутили арифмометры, считая что-то. Где-то прослышав про первые ЭВМ, Лавров стал ими интересоваться, увлекся и в конце концов сменил внешнюю баллистику на программирование, сделав первый транслятор. Потом в Новосибирске Андрей Петрович Ершов создал оптимизирующий транслятор Альфа. Говорят, его даже американцы признавали лучшим оптимизирующим транслятором. Потом в Москве сделали ТА2 с полного Алгола 60, но к этому моменту полный Алгол 60 с его дурацкими чертами никому не был нужен. Насколько я знаю, ТА2 так и не использовали, а на лавровском трансляторе ТА1М я работал много лет. У нас на матмехе было две машины М 20, на них стоял ТА1М, который потом стали называть Сигнал.

ПЛ/1


Американцы озлобились, когда в Европе появился Алгол 60, и сделали PL/I (Programming Language I Язык программирования номер один). Кошмарный язык! Сотни автоматических преобразований типов в другие типы. Как говорили, язык-оболочка. Несколько сот операторов: на любой чих отдельный оператор кто их все запомнит? Тем не менее этот язык стал довольно популярным и в СССР, поскольку появились ЕС ЭВМ. Я писал на нем, но тоже кошмарики случались. Опишешь в одной процедуре глобальную переменную А bin fix (целое), а в другой переменную А bin float (с плавающей точкой). Потом будешь долго искать ошибку транслятор ничего не скажет.

Короче, ПЛ/1 и в Европе сильно не любили, не только в СССР. Я много раз бывал в США и слышал, что не бывает капиталистического и коммунистического программирования, но бывают разные стили.

Американский стиль метод грубой силы. Когда человеку не хватает вычислительной мощности машины, он идет к начальнику и говорит: Купи-ка мне машину в два раза более мощную. Обычно ее действительно покупают.

В Европе и в СССР, естественно это не было принято. Надо было головой подумать, найти более эффективный алгоритм.

Я как-то познакомился с главным конструктором трансляторов с ПЛ/1. Его фамилия Маркс советскому человеку легко запомнить. Он не американец, англичанин, а трансляторы эти делались недалеко от Лондона там был центр IBM в Европе. Познакомились мы с ним в Новосибирске, где была большая конференция, на которой Маркс делал доклад. Его спросили: Сколько было найдено ошибок в процессе отладки? Он: Не могу на этот вопрос ответить секрет фирмы. А сколько людей у вас было? Ответ тот же. Тут вскакивает Кес Костер, один из авторов Алгола 68 (я был прикреплен к нему как переводчик), и начинает орать на довольно специфическом английском, который сейчас все дети знают: Вы позорите наш свободный мир перед лицом этих забитых коллег. И мне: Переводи! Я: У нас так не принято, Кес. Тебя ко мне приставили, вот и переводи! Ах так? Я стал переводить, как понял, а понял я довольно точно. Но никто меня не осудил. Потом был перерыв с кофе и коньяком стаканами тогда так было принято. Стоит этот бедный Маркс, а вокруг метра два пустоты. Подхожу к нему с двумя емкостями: Давай выпьем! Он хлопнул стакан и говорит: Давай я тебе все расскажу. В частной беседе могу, а с трибуны нельзя. И вот он рассказал, что был у него 51 программист, что нашли столько-то ошибок, что это такая дикая структура транслятор с ПЛ/1.

Потом выяснилось, что у нас много общего. Оба 1949 года рождения, оба в 1971-м окончили университеты он Лондонский, я Ленинградский. Я говорю: Как же так? По времени трансляции мы выигрываем у тебя в четыре раза, по скорости счета в три, по длине кода в бесконечное число раз. Почему вы такие глупые? Он: А сколько лет ты работал над транслятором с Алгола 68? Лет семь. У нас бы тебя давно с работы выгнали. Год гони товар, иначе будешь на улице. Тогда я впервые узнал, что такое Time to Market. Важно работать быстро, иначе кто-то займет эту нишу на рынке. Потом ты сделаешь лучше, но никто об этом уже не узнает. В СССР мы этого не знали.

Алгол 68


Европейцы на PL/I ответили языком Алгол 68. Была такая рабочая группа 2.1 IFIP по алголоподобным языкам. Когда в 1964 году опубликовали пересмотренное сообщение об Алголе 60, решили, что это направление кончилось, надо развивать что-то совсем другое. Кинули клич: что будем делать дальше? Ответом стала Белая книга у меня на полке стоит, раритет, в интернете нет с предложениями той самой группе 2.1.

В ней есть большая статья Ральфа Лондона о доказательствах корректности программ, статья Барбары Лисков Язык CLU, где она впервые сформулировала понятие абстрактных типов данных. Там же была статья голландского ученого ван Вейнгаардена о двухуровневых грамматиках. Двухуровневая грамматика как машина Тьюринга по мощности, с ее помощью можно описать не только точный синтаксис сейчас этим никого не удивишь но и точную семантику исполнения языка. И вот после многих совещаний люди из рабочей группы 2.1 решил взять за основу будущего языка двухуровневые грамматики ван Вейнгаардена. Сказано сделано.

Группа включала порядка 200 человек, в том числе, советских ученых: Ершова, Лаврова. Очень много писем участникам писал мой научный руководитель Григорий Самуилович Цейтин они ему даже благодарность выдали. В декабре 1968 года IFIP приняла новый язык, названный Алгол 68.

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

И вот приходит к нам в лабораторию системного программирования, в которой я тогда работал, будучи студентом 3-го курса матмеха, Григорий Самуилович Цейтин и говорит: Ребята, тут такой язык придумали никто его реализовать не может. Давайте его реализуем. Мы: Давайте, и занялись этим делом. Мой диплом в 1971 году назывался Поиск цепочки приведений в трансляторе с Алгола 68 для ЕС ЭВМ. 11 страниц рукописного текста и работающая программа. Лет через пять я в этом дипломе нашел ошибку, но, когда защищался, никто ее не заметил.

Очень тяжелый был язык, и не одни мы так считали. Группа 2.1 продолжила работу, и в 74 году было издано пересмотренное сообщение об Алголе 68. Еще шесть лет напряженной работы большого комитета. Этот язык уже получился вполне понятным, его стали реализовывать во многих группах и в Европе, и в Америке. В СССР была группа Михаила Рувимовича Левинсона в ЦЭМИ, Екатерины Логвиновны Ющенко в Киеве. Саша Маслов с командой делали Алгол 68 для Эльбруса. Андрей Петрович Ершов создавал оптимизирующий транслятор с Алгола 68 в Новосибирске. В Ленинграде, когда Григорий Цейтин от этих работ отошел, задача в буквальном смысле свалилась на меня.


Алгол: успехи и неудачи, конспект доклада швейцарского ученого Петера Наура, представленного на коллоквиуме 10 лет Алгола в Цюрихе 31 мая 1968 года. Из архива академика Андрея Ершова

Кого-то подсиживать, чтобы стать руководителем лаборатории, мне не пришлось. Все получилось само собой, когда мы начали делать отладку IBM/360 в московском НИЦЭВТ. У нас был доктор наук, штук пять кандидатов и около 15 студентов, пока мы писали статьи и книги, все было хорошо. Но потом люди старшего поколения потихонечку стали отваливаться. Время в НИЦЭВТ нам выделяли только ночью. Ездили в Москву на три дня ночью работаем, днем спим, но молодым было все равно. Более того, я любил работать ночью. Там стояли американские и советские устройства. Перекинешь кабель, и работаешь нормально на хорошем американском оборудовании, а утром переключаешь обратно. Днем такого делать не давали. А коллеги постарше ночного режима не выдержали: когда сдавали транслятор, я уже был и главным конструктором, и руководителем лаборатории.

Первый в СССР транслятор с Алгола 68 сделали мы. С некоторым отставанием группы Маслова и Левинсона. Ющенко сделала интересную разработку, совмещенную с базой данных. В Новосибирске провели огромное научное исследование, называвшееся Бета проект. Они пытались сильно обобщить задачу, чтобы одним транслятором можно было сделать и Алгол 68 и PL/I, и Паскаль. И в коды БЭСМ-6, и в коды ЕС ЭВМ. Полностью проект так и не был завершен, но какие-то одиночные трансляторы они сделали.

Когда мы начали заниматься внедрением Алгола 68, выяснилось, что его надежность никому особенно не нужна, кроме военных. Но вот они клюнули, и многие военные организации на него перешли.


Оглавление Пересмотренного сообщения об Алголе 68, изданного рабочей группой 2.1. Первым в списке редакторов указан Адриан ван Вейнгаарден

Паскаль


Одним из участников рабочей группы 2.1 был Никлаус Вирт. Он, и еще несколько известных ученых Хоар, Дейкстра, к сожалению, наш Лавров не согласились с мнением большинства и в декабре 1968-го написали так называемый Minority Report. В нем они выразили мысль, что гора родила мышь: этот язык такой большой и сложный, что его никогда в жизни никто не поймет. На самом деле, это правда, но после шести лет работы и выхода Пересмотренного cообщения Алгол 68 превратился во вполне симпатичный и понятный язык. В академических кругах он приобрел довольно широкую популярность, а в промышленном программировании, особенно в Америке нет. И вот товарищ Вирт сделал такой финт ушами создал язык, который назвал Паскаль. Сам он из Цюриха, но в тот момент стажировался в Стэнфорде.

Паскаль обрезыш Алгола 68. Т. е. взял ножницы, отрезал это, это, это Первое описание было как тетрадочка за 2 копейки: 24 листа, тоненько-тоненько. Поскольку к тому времени мы уже завершали работу над Алголом 68, один из моих учеников взялся реализовать нашими же методами и Паскаль. Но каждое утро начиналось с его вопросов ко мне: почему между repeat и until можно написать много операторов без дополнительных скобок, а после do только один?, почему после else можно писать if, а после then нельзя?, что делать, если я хочу передать процедуре параметром саму себя, например, для вычисления кратного интеграла?. Нестыковок было много. В Алголе 68 были ограничения, чтобы бесконечная память не получалась, чтобы не получалось самоприведение. В Паскале нет.

В те годы в СССР был популярен анекдот: Работаю на кроватном заводе, каждый день детальки домой таскаю, хочу кровать сделать, но, как ни соберу, пулемет получается. Так вот, когда мы стали чинить Паскаль, получился Алгол 68. Все смеялись, говорили, что странно, а я как раз ничего удивительного в этом не нахожу. Просто над Алголом 68 работали три сотни людей много лет, и мы в том числе.

Забавно, что моя жена писала Кесу Костеру, автору секции обмена, про найденные ею ошибки и получала ответы: Дорогой мистер Терехова. Сначала мы обижались, а потом нам сказали: А как он догадается, что Терехова это она? Тогда мы стали подписывать Галия Терехова, и он все понял.

Вирт умный мужик, он работал над уточнением Паскаля, и в 1974 году вместе с человеком по фамилии Йенсен сделал стандарт потолще, страниц 100120. Когда Вирт праздновал 80-летие, в Цюрихе был маленький симпозиум, куда среди 2030 гостей пригласили и меня. Когда приехал, оказалось, что Йенсен женщина, Кетлин. Честно говоря, для меня это было неожиданностью. Она очень много сделала для превращения Паскаля из игрушки в серьезный язык.


Выступление Кетлин Йенсен на симпозиуме, посвященном 80-летию Никлауса Вирта

Потом за дело взялась фирма Borland и сделала Borland Pascal уже два толстых тома. Так появился язык, которым уже можно было пользоваться. До этого школьное баловство.

Когда вышло пересмотренное сообщение о Паскале Вирта и Йенсен тоже через несколько лет после публикации первого стандарта в предисловии Вирт писал: Паскаль имеет уровень выше, чем Алгол 60. Редактором перевода был известный советский программист Дмитрий Подшивалов, довольно злой дяденька. Любил резко высказаться. После реплики Вирта в переводе появилась сносочка: С этим утверждением трудно согласиться. Попробуйте на Паскале написать процедуру умножения матриц. Дело в том, что в Паскале, как и в Си, кстати, можно массив описать от нуля до ста, до тысячи, но нельзя до N нет динамических массивов. А как вы опишете процедуру умножения матриц? Вы же не знаете, какие матрицы пойдут умножаться. Поэтому Подшивалов был абсолютно прав. Тоже мне, язык более высокого уровня, на котором нельзя написать процедуру умножения матриц!


Николаус Вирт и компьютер Лилит, разработанный в Швейцарской высшей технической школе Цюриха. Специально для реализации ПО этой системы Вирт создал новый язык Модула-2. 1981 г.

Паскаль в конце концов стал очень популярным у школьников и студентов. Для начального обучения программированию он и правда хорош. Для чайников надежность мало что значит: подумаешь, дырка в языке одна, вторая, третья. Зато его можно легко прочитать и что-то написать. В промышленное программирование Паскаль так, по-моему, и не пошел туда, где требуется ответственность и нужно писать большие программные комплексы с высокой надежностью.

Ада


После того как европейцы сделали Алгол 68, американцы решили а чем мы хуже? И решили создать новый язык для министерства обороны США. Оно и сейчас самый большой заказчик IT в мире, поскольку ни одна компания не может сравниться с ним по объемам финансирования. Американцы решили подойти к этому по науке. Сначала сформулировать требования к языкам. Они назывались так: соломенный человек, деревянный человек, стальной человек. И последний каменный. Я читал эти толстые тома, сформулировано четко и хорошо.

Потом объявили конкурс с многомиллионным призом. Но они понимали, если не принять специальных мер, однозначно победит IBM. Это как в поговорке про футбол: Играют все, а побеждают немцы. В те годы у IBM финансовый оборот был раз в 20 больше, чем у ближайшего конкурента. Еще говорили IBM и 6 гномов: одна компания с оборотом в 16 млрд и еще шесть по 1 млрд. Т. ч. IBM всех бы задавила. Поэтому министерство обороны засекретило участников, никто не знал, кто есть кто. На первом этапе выбрали 17 команд. Дали им довольно большое финансирование миллионы долларов каждой. На втором этапе отобрали четыре команды и назвали по цветам: красная желтая, зеленая, голубая. Их финансирование уже исчислялось миллиардами, а сделать они должны были не только язык, но и пробный транслятор, чтобы можно было провести апробацию. Только когда они завершили работу, конверты открыли.

Случился дикий скандал, потому что внезапно победили европейцы, команда Жана Ишбиа из Парижа. С языком, который очень похож на Алгол 68 и совершенно не похож на PL/1. Язык назвали Ада в честь первой программистки мира Ады Лавлейс, помощницы Чарльза Бэббиджа и, кстати, дочки лорда Байрона, но это вы, наверное, хорошо знаете.


Жан Давид Ишбиа был сотрудником научно-исследовательского подразделения французской компании-производителя компьютерной техники Bull

Для создания всех этих стоун менов, т. е. формулирования требований, американцы собирали комитеты. Нужны были сотни специалистов, чтобы все это дело оценивать. Поэтому из Европы программистов переманивали в США целыми группами. В одном из комитетов попался коммунист венгр Иван Бах, член венгерской социалистической рабочей партии, оказался практически в Пентагоне. Я в 1976 году читал лекции в Будапештском университете, там меня с ним познакомили. Мы сдружились, гуляли по Будапешту, и он мне рассказывал, как все у американцев устроено. В конце концов он скинул мне на магнитную ленту одно из предварительных описаний языка Ада. Над ним еще года три работали потом. Опять-таки, вспомните про цифру 6.

И вот я привез в СССР первое в стране описание языка Ада. Мы, естественно, решили делать транслятор. Я уже в этом деле поднаторел и подумал: раз это стандарт министерства обороны США, наверняка и наши вояки захотят его использовать. Тут я им и скажу: У меня есть транслятор. Но я сильно промахнулся наши вояки Адой не заинтересовались. По-моему, зря. Всё воровали надо было и это спереть.

Когда решил делать транслятор, один сотрудник моей лаборатории, года на четыре старше меня, говорит: Андрей, ты много руководил. Что ты все под себя да под себя? Дай я буду руководить этой работой. Отвечаю: Я привез, продумал, знаю, как делать. Но ладно, руководи. Уговорил он меня, а мне и так было чем заняться. Прошло три месяца и выяснилось, что группу, созданную под Аду, возглавляет уже выпускник чуть ли не этого года. Это был мой ученик Аркадий Попов. Я спрашиваю: Как так? Зачем сопляку передал? А он: Я не передал у меня отобрали. Молодой человек оказался очень активным.

Но на этом история не заканчивается. Молодой человек говорит мне: Андрей, ты руководитель неправильный. Мы все делаем прототипами, быстро хотим что-то увидеть. Надо по науке: создать проект и идти по нему. Я: Руководишь делай. Заодно и посмотрим.

Группа из четырех человек два года писала на печатной машинке три толстых тома проект. Мы приглядывали за молодыми, радовались за них, по окончании проектирования даже небольшую пьянку устроили. Торжественный момент завершена двухлетняя работа. Но прошло три месяца реализации, и оказалось, что они в проекте ошиблись, причем в какой-то структуре данных, которая сильно влияет на все остальное. Аркадий пришел ко мне, попросил прощения: Мы обмишурились. Но эта группа все-таки сделала первый в СССР транслятор с языка Ада. Правда, позже, чем собиралась, и уже нормальными способами, как все.


Олег Перминов, Введение в язык программирования АДА, 1991 г.

Java и Python


На этом мои любимые языки заканчиваются. Дальнейший путь уже не был таким революционным.

Допустим, Java. Основан на виртуальной машине, на переносимости кода. Даже в Википедии написано, что p-коды придуманы где-то в 1978 году. Но нет! Я спрашивал самого Вирта лично, кто придумал p-код. Он ответил: Я придумал. Когда сделал Паскаль, он пришел к ректору Стэнфордского университета: Есть язык, на котором можно хорошо учить студентов. Давайте? Ректор: Давайте! Только у меня шесть типов компьютеров. Сделайте, чтобы Паскаль был на всех. Вирт говорил, что чуть не умер сделать шесть трансляторов в одиночку невозможно. И вот тогда он создал p-код, виртуальную машину. Получилось, что у него есть транслятор с Паскаля в p-код, написанный на p-коде, а потом на каждой машине сделан интерпретатор p-кода это совсем простая ассемблерная программа, несколько сот строк. И все заработало. Мы до сих пор этой идеей пользуемся. Никлас утверждает, что p-код придумал именно он, и не в 78 году, а в 71-м. Я тоже слышал о p-коде в начале 70-х какая-то информация до нас доходила.

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

О Питоне я скажу всего пару слов. Это язычок, на котором нельзя писать большие программы. Зато он очень хорош для прототипирования: быстренько на коленке сверстать и посмотреть, что получится. Так им и пользуются, в основном. Облегченный язык, на котором накоплено огромное количество библиотек. Но я не представляю, чтобы на Питоне написали управление ракетой или телефонной станцией для большой аппаратной системы он не предназначен. Собственно, об этом мне и сам Гвидо ван Россум говорил, когда рассказывал, как и для чего Питон придумывал.

Си


Несколько подробнее остановлюсь на истории языка Си одном из самых популярных. Кен Томпсон в 1970 году придумал операционную систему, которая теперь называется Юникс. Это было крутое событие. Для этого он использовал бестиповой язык Би. Чуть позже Мартин Ричард придумал язык BCPL развитие языка Би, тоже бестиповое. Потом Деннис Ритчи решил переписать все на более эффективном и надежном языке Си, который сам же и придумал. Он опирался на Би и BCPL, но добавил типовой контроль.


Создатели операционной системы UNIX Кен Томпсон и Деннис Ритчи за работой на PDP-11. Фото Питера Хаммера, около 1970 г.

Получилось забавно. Первая публикация Ричи вышла в 1978 году, когда Си уже стал популярен и даже до СССР дошел. Я знал Си, потому что исходные тексты Юникса распространялись свободно это был первый опыт опенсорс-проекта. Си люди изучали следующим образом: почитали массив пишется так, вырезка так, цикл так. Все, больше ничего не надо. Но первая статья автора языка появилась только спустя несколько лет после того, как в мире с ним уже все близко познакомились.

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

Кобол



Обложка доклада о языке Кобол, подготовленного Министерством обороны США для конференции в апреле 1960 года

Кобол, это исчадие ада, тоже изобрели американцы. Дело в том, что Фортран изначально был придуман для научных расчетов, а у американцев уже в те годы многие компьютеры использовались в экономике для управления производством. Кобол придумали специально для работы с экономическими данными.

Язык очень странный, но для экономических расчетов оказался хорош. Можно сколько угодно говорить, что он дырявый и неаккуратный, но на нем написана половина финансовых программ мира, Центральный банк России и Сбербанк тоже работают на Коболе. Мне это хорошо известно, поскольку повсюду мои ученики. Новых программ на нем не пишут, но есть тонны старых.

Кобол дал мне возможность выжить в перестроечное время. К концу 1980-х у нас была мощная группа трансляторов первые трансляторы с Алгола 68, с Ады, с языков искусственного интеллекта, управления роботами. Всё было хорошо, но грянула перестройка, и сюда хлынул поток программ из США. Американские трансляторы заполонили рынок, а поскольку никто ни за что не платил это была эпоха сплошного пиратства про мою команду стали забывать. Я почти отчаялся, хотя к тому времени образовал предприятие Терком Терехов и команда.

Я бы, наверное, пропал, но тут у американцев появилась бизнес-проблема. У них были накоплены тонны программ на Коболе, но их сопровождение оказалось очень дорогостоящим, этот язык мало кто знает. И тогда они решили сделать такой реинжиниринг перевести кобольские программы на современные платформы. Попытались в Университете Дьюка, но не сумели справиться. Но в их компании нашелся выходец из СССР. Вообще, я только на шестой или седьмой поездке в США встретил американца, родившегося в Америке. Леня Эрлих, бывший одессит, сказал: Если не могут американцы, может, у русских получится. И у нас получилось. В общем язык чудовищный, зато помог мне выжить в трудную пору.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru