Я собираюсь выполнить побочный проект, целью которого является перевод кода с одного языка программирования на другой. Языки, с которых я начинаю, - это PHP и Python (с Python на PHP должно быть легче начать), но в идеале я мог бы добавить другие языки с (относительной) легкостью. План такой:
Это ориентировано на веб-разработку. Исходный и целевой код будут находиться поверх фреймворков (которые мне также придется написать). Эти платформы будут охватывать шаблон проектирования MVC и следовать строгим соглашениям о кодировании. Это должно несколько упростить перевод.
Я также смотрю на IOC и внедрение зависимостей, так как они могут упростить процесс перевода и уменьшить вероятность ошибок.
Я буду использовать модуль синтаксического анализатора Python , который позволяет мне возиться с абстрактным синтаксическим деревом. По-видимому, самое близкое, что я могу найти с PHP, - это token_get_all () , что является началом.
С этого момента я могу создавать AST, таблицы символов и поток управления.
Тогда я думаю, что могу начать выводить код. Мне не нужен идеальный перевод . Мне все равно придется просмотреть сгенерированный код и исправить проблемы. В идеале переводчик должен отмечать проблемные переводы.
Прежде чем вы спросите: "Какой в этом черт смысл?" Ответ ... Это будет интересный опыт обучения. Если у вас есть идеи, как сделать это менее пугающим, дайте мне знать.
РЕДАКТИРОВАТЬ:
Меня больше интересует, какие типы шаблонов я могу применить к коду, чтобы упростить перевод (например, IoC, SOA?) Кода, чем то, как сделать перевод.
источник
Ответы:
Я занимаюсь созданием инструментов (DMS Software Reengineering Toolkit) для манипуляций с программами общего назначения (особый случай - языковой перевод) с 1995 года при поддержке сильной команды компьютерных ученых. DMS обеспечивает общий синтаксический анализ, построение AST, таблицы символов, управление и анализ потока данных, применение правил перевода, регенерацию исходного текста с комментариями и т. Д., Все параметризованные явными определениями компьютерных языков.
Количество оборудования, которое вам нужно для этого хорошо , огромно (особенно если вы хотите иметь возможность делать это для нескольких языков в общем виде), и тогда вам нужны надежные парсеры для языков с ненадежными определениями (PHP - прекрасный пример этого. ).
Нет ничего плохого в том, что вы думаете о создании переводчика с одного языка на другой или пытаетесь это сделать, но я думаю, что для реальных языков это будет гораздо более сложной задачей, чем вы ожидаете. Мы потратили около 100 человеко-лет только на DMS и еще 6–12 месяцев на каждое «надежное» определение языка (включая то, которое мы с трудом создали для PHP), и намного больше для неприятных языков, таких как C ++. Это будет «адский опыт обучения»; это было для нас. (Возможно, вам будет интересен раздел технических статей на указанном выше веб-сайте, чтобы начать это обучение).
Люди часто пытаются создать какой-то универсальный механизм, начиная с некоторой части технологии, с которой они знакомы и которая выполняет часть работы. (Python AST - отличный пример). Хорошая новость в том, что часть работы сделана. Плохая новость заключается в том, что в механизм встроен миллион предположений, большинство из которых вы не обнаружите, пока не попытаетесь заставить его делать что-то еще. В этот момент вы обнаруживаете, что механизм настроен на то, что он делает изначально, и действительно, действительно сопротивляется вашей попытке заставить его делать что-то еще. (Я подозреваю, что попытка заставить Python AST моделировать PHP будет очень весело).
Причина, по которой я начал создавать DMS изначально, заключалась в том, чтобы построить фундамент, в котором было очень мало таких допущений. Некоторые из них доставляют нам головную боль. Пока нет черных дыр. (Самая сложная часть моей работы за последние 15 лет - попытаться предотвратить появление таких предположений).
Многие люди также ошибаются, полагая, что, если они могут анализировать (и, возможно, получить AST), они хорошо на пути к выполнению чего-то сложного. Один из трудных уроков состоит в том, что вам нужны таблицы символов и анализ потока, чтобы проводить хороший анализ или преобразование программы. AST необходимы, но недостаточны. Это причина того, что книга компиляторов Ахо и Ульмана не ограничивается главой 2. (ОП имеет на это право в том смысле, что он планирует построить дополнительные механизмы помимо AST). Для получения дополнительной информации по этой теме см. Жизнь после анализа. .
Замечание о том, что «мне не нужен идеальный перевод», вызывает беспокойство. Что делают слабые переводчики, так это конвертируют «простые» 80% кода, оставляя сложные 20% делать вручную. Если приложение, которое вы собираетесь преобразовать, довольно маленькое, и вы собираетесь преобразовать его только один раз, то эти 20% в порядке. Если вы хотите преобразовать много приложений (или даже одно и то же с небольшими изменениями со временем), это нехорошо. Если вы попытаетесь преобразовать 100K SLOC, то 20% - это 20 000 исходных строк кода, которые трудно перевести, понять и изменить в контексте еще 80 000 строк переведенной программы, которую вы уже не понимаете. Это требует огромных усилий. На уровне миллиона строк это просто невозможно на практике.сложнее, и обычно они выясняют это болезненно, с длительными задержками, высокими затратами и часто откровенными неудачами.)
Для перевода крупномасштабных систем вам нужно стремиться к высокому проценту конверсии в девяностые годы, иначе вы, вероятно, не сможете выполнить ручную часть переводческой деятельности.
Еще одно важное соображение - это размер транслируемого кода. Даже с хорошими инструментами для создания работающего надежного переводчика требуется много энергии. Хотя создание переводчика вместо простого ручного преобразования кажется привлекательным и крутым, для небольших баз кода (например, примерно до 100 тыс. SLOC по нашему опыту) экономия просто не оправдывает этого. Никому не нравится этот ответ, но если вам действительно нужно перевести всего 10K SLOC кода, вам, вероятно, лучше просто укусить пулю и сделать это. И да, это больно.
Я считаю наши инструменты очень хорошими (но тогда я довольно пристрастен). А создать хорошего переводчика по-прежнему очень сложно; на это у нас уходит 1,5–2 человеко-года, и мы знаем, как использовать наши инструменты. Разница в том, что с таким большим количеством машин мы добиваемся успеха гораздо чаще, чем терпим поражение.
источник
Мой ответ будет касаться конкретной задачи синтаксического анализа Python, чтобы перевести его на другой язык, а не аспектов более высокого уровня, которые Ира хорошо рассмотрел в своем ответе.
Вкратце: не используйте модуль парсера, есть способ попроще.
ast
Модуль доступен с Python 2.6 гораздо больше подходит для ваших нужд, так как она дает готовый AST для работы с. Я написал статью об этом в прошлом году, но, короче говоря, используйтеparse
методast
для синтаксического анализа исходного кода Python в AST.parser
Модуль даст вам дерево разбора, не является AST. Остерегайтесь разницы .Теперь, поскольку AST Python довольно подробны, с учетом AST работа с интерфейсом не так уж и сложна. Я полагаю, у вас может быть простой прототип для некоторых частей функциональности, готовый довольно быстро. Однако получение полного решения займет больше времени, в основном из-за разницы в семантике языков. Простое подмножество языка (функции, базовые типы и т. Д.) Можно легко перевести, но как только вы перейдете на более сложные уровни, вам понадобится тяжелая техника для эмуляции ядра одного языка в другом. Например, рассмотрим генераторы Python и списки, которых нет в PHP (насколько мне известно, что, по общему признанию, плохо, когда задействован PHP).
Чтобы дать вам последний совет, рассмотрим
2to3
инструмент, созданный разработчиками Python для перевода кода Python 2 в код Python 3. Что касается внешнего интерфейса, в нем есть большинство элементов, необходимых для перевода Python во что-то . Однако, поскольку ядра Python 2 и 3 схожи, никаких механизмов эмуляции там не требуется.источник
2to3
это просто AST для AST. Он не поддерживает выполнение каких-либо действий, выходящих за рамки возможностейast
модуля. Обратите внимание, что все переводы идут от синтаксиса, поддерживаемого хост-процессом python, до синтаксиса, поддерживаемого хост-процессом python. Нет переводчика, который бы добавил, скажем, аннотации функций, потому что 2.6 не поддерживает его.2to3
можно рассматривать как пример использования AST, созданного изast
.Написать переводчика не невозможно, особенно учитывая, что стажер Джоэла сделал это за лето.
Если вы хотите работать на одном языке, это просто. Если вы хотите сделать больше, это немного сложнее, но не слишком много. Самая сложная часть состоит в том, что, хотя любой полный язык по Тьюрингу может делать то, что делает другой полный язык по Тьюрингу, встроенные типы данных могут феноменально изменить то, что делает язык.
Например:
требует много кода C ++ для дублирования (хорошо, ну, вы можете сделать это довольно быстро с некоторыми конструкциями цикла, но все же).
Думаю, это немного отступление.
Вы когда-нибудь писали токенизатор / парсер на основе языковой грамматики? Вы, вероятно, захотите узнать, как это сделать, если вы этого не сделали, потому что это основная часть этого проекта. Что бы я сделал, так это придумал базовый полный синтаксис Тьюринга - что-то очень похожее на байт-код Python . Затем вы создаете лексический анализатор / анализатор, который принимает грамматику языка (возможно, используя BNF ) и на основе грамматики компилирует язык в ваш промежуточный язык. Затем вам нужно сделать обратное - создать синтаксический анализатор вашего языка на целевые языки на основе грамматики.
Самая очевидная проблема, которую я вижу, заключается в том, что сначала вы, вероятно, создадите ужасно неэффективный код, особенно на более мощных * языках, таких как Python.
Но если вы сделаете это таким образом, вы, вероятно, сможете найти способы оптимизации вывода по мере продвижения. Подвести итоги:
* под мощным я подразумеваю, что это занимает 4 строки:
Покажите мне другой язык, который может делать что-то подобное, в 4 строки, и я покажу вам язык, столь же мощный, как Python.
источник
Есть пара ответов, которые говорят вам не беспокоиться. Насколько это полезно? Ты хочешь учиться? Ты можешь выучить. Это компиляция. Так уж случилось, что ваш целевой язык - это не машинный код, а другой язык высокого уровня. Это происходит постоянно.
Есть относительно простой способ начать. Сначала перейдите по адресу http://sourceforge.net/projects/lime-php/ (если вы хотите работать на PHP) или что-то подобное и просмотрите пример кода. Затем вы можете написать лексический анализатор, используя последовательность регулярных выражений, и передать токены в сгенерированный вами синтаксический анализатор. Ваши семантические действия могут либо выводить код непосредственно на другом языке, либо создавать некоторую структуру данных (мыслить объекты, человек), которые вы можете массировать и перемещаться для генерации кода вывода.
Вам повезло с PHP и Python, потому что во многих отношениях это один и тот же язык, но с другим синтаксисом. Труднее всего преодолеть семантические различия между грамматическими формами и структурами данных. Например, в Python есть списки и словари, а в PHP - только ассоциативные массивы.
Подход «учащийся» состоит в том, чтобы создать что-то, что работает нормально для ограниченного подмножества языка (например, только операторы печати, простую математику и присвоение переменных), а затем постепенно снимать ограничения. Это в основном то, что делали все «большие» ребята в этой области.
Да, и поскольку у вас нет статических типов в Python, возможно, лучше написать и полагаться на функции PHP, такие как «python_add», которые добавляют числа, строки или объекты в соответствии с тем, как это делает Python.
Очевидно, это может стать намного больше, если вы позволите этому.
источник
Я поддержу точку зрения @EliBendersky относительно использования ast.parse вместо парсера (о котором я раньше не знал). Я также настоятельно рекомендую вам просмотреть его блог. Я использовал ast.parse для перевода Python-> JavaScript (@ https://bitbucket.org/amirouche/pythonium ). Я придумал Pythonium дизайн на несколько обзор других реализаций и пытается их самостоятельно. Я раздвоил Pythonium из https://github.com/PythonJS/PythonJS, который я также начал, это фактически полная переписывание. Общий дизайн вдохновлен PyPy и http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-89-1.pdf бумагой.
Все, что я пробовал, от начала до лучшего решения, даже если это похоже на маркетинг Pythonium, на самом деле это не так (не стесняйтесь сказать мне, если что-то не кажется правильным для сетевого этикета):
Реализуйте семантику Python в обычном старом JavaScript с использованием наследования прототипов: AFAIK невозможно реализовать множественное наследование Python с использованием объектной системы прототипов JS. Позже я попытался сделать это, используя другие приемы (см. Getattribute). Насколько мне известно, в JavaScript нет реализации множественного наследования Python, лучшее, что существует, - это одиночное наследование + миксины, и я не уверен, что они обрабатывают наследование алмаза. Вроде как Skulpt, но без закрытия Google.
Я пробовал использовать Google clojure, точно так же, как Skulpt (компилятор), вместо того, чтобы читать код Skulpt #fail. Во всяком случае, из-за объектной системы на основе прототипа JS все еще невозможно. Создание привязки было очень и очень сложным, вам нужно было написать JavaScript и много шаблонного кода (см. Https://github.com/skulpt/skulpt/issues/50, где я - призрак). В то время не было четкого способа интегрировать привязку в систему сборки. Я думаю, что Skulpt - это библиотека, и вам просто нужно включить свои файлы .py в html для выполнения, разработчик не требует выполнения этапа компиляции.
Пробовал pyjaco (компилятор), но создание привязок (вызов кода Javascript из кода Python) было очень трудным, слишком много шаблонного кода для создания каждый раз. Теперь я думаю, что pyjaco - это тот, который ближе к Pythonium. pyjaco написан на Python (в том числе ast.parse), но многое написано на JavaScript и использует наследование прототипов.
На самом деле мне никогда не удавалось запустить Pyjamas #fail, и я никогда не пытался снова прочитать код #fail. Но на мой взгляд, пижама выполняла перевод API-> API (или фреймворка в фреймворк), а не перевод Python в JavaScript. Инфраструктура JavaScript использует данные, которые уже есть на странице, или данные с сервера. Код Python - это всего лишь «сантехника». После этого я обнаружил, что pajamas на самом деле был настоящим переводчиком python-> js.
Тем не менее, я думаю, что можно сделать перевод API-> API (или framework-> framework), и это в основном то, что я делаю в Pythonium, но на более низком уровне. Вероятно, Pyjamas использует тот же алгоритм, что и Pythonium ...
Затем я обнаружил, что brython полностью написан на Javascript, как Skulpt, не требует компиляции и лишен всякой ерунды ... но написан на JavaScript.
С момента написания начальной строки в ходе этого проекта я знал о PyPy, даже о бэкэнде JavaScript для PyPy. Да, вы можете, если найдете, напрямую сгенерировать интерпретатор Python в JavaScript из PyPy. Говорят, это была катастрофа. Я не читал где почему. Но я думаю, причина в том, что промежуточный язык, который они используют для реализации интерпретатора, RPython, представляет собой подмножество Python, адаптированное для перевода на C (и, возможно, asm). Ира Бакстер говорит, что вы всегда делаете предположения, когда создаете что-то, и, вероятно, вы точно настраиваете его, чтобы он был лучшим для того, что он должен делать в случае перевода PyPy: Python-> C. Эти предположения могут не иметь отношения к другому контексту, хуже того, что они могут приводить к накладным расходам, в противном случае прямой перевод, скорее всего, всегда будет лучше.
Написание интерпретатора на Python звучало как (очень) хорошая идея. Но меня больше интересовал компилятор по соображениям производительности, а также на самом деле компилировать Python в JavaScript проще, чем интерпретировать его.
Я начал PythonJS с идеей собрать подмножество Python, которое я мог бы легко перевести на JavaScript. Сначала я даже не стал внедрять объектно-ориентированную систему из-за прошлого опыта. Подмножество Python, которое мне удалось перевести на JavaScript:
Это кажется большим, но на самом деле очень узким по сравнению с полноценной семантикой Python. Это действительно JavaScript с синтаксисом Python.
Сгенерированный JS идеален, т.е. нет накладных расходов, его нельзя улучшить по производительности дальнейшим редактированием. Если вы можете улучшить сгенерированный код, вы также можете сделать это из исходного файла Python. Кроме того, компилятор не полагался на какие-либо уловки JS, которые вы можете найти в .js, написанном http://superherojs.com/. , поэтому он очень удобочитаемый.
Прямым потомком этой части PythonJS является режим Pythonium Veloce. Полную реализацию можно найти по адресу https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/veloce/veloce.py?at=master. 793 SLOC + около 100 SLOC общего кода с другим переводчиком.
Адаптированная версия pystones.py может быть переведена в режиме Veloce cf. https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pystone/?at=master
После настройки базового перевода Python-> JavaScript я выбрал другой путь для перевода полного Python в JavaScript. Способ glib создания объектно-ориентированного кода на основе классов, за исключением того, что целевой язык - это JS, поэтому у вас есть доступ к массивам, объектам, подобным карте, и многим другим трюкам, и все это было написано на Python. IIRC нет кода javascript, написанного в переводчике Pythonium. Получить единичное наследование несложно, вот те сложные моменты, которые делают Pythonium полностью совместимым с Python:
spam.egg
в Python всегда переводится на то, чтоgetattribute(spam, "egg")
я не профилировал это в частности, но я думаю, что там, где он теряет много времени, и я не уверен, что смогу улучшить его с помощью asm.js или чего-то еще.Эта часть учтена в https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/runtime.py?at=master Он написан на Python, совместимом с Python Veloce.
Фактически совместимый переводчик https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/compliant.py?at=master не генерирует код JavaScript напрямую и, самое главное, не выполняет преобразование ast-> ast . Я пробовал использовать ast-> ast, и ast, даже если он лучше, чем cst, нехорошо работать даже с ast.NodeTransformer и, что более важно, мне не нужно делать ast-> ast.
Выполнение python ast в python ast в моем случае, по крайней мере, может быть улучшением производительности, поскольку я иногда проверяю содержимое блока перед генерацией связанного с ним кода, например:
Поэтому я не посещаю каждый узел один раз на каждом этапе перевода.
Общий процесс можно описать как:
Встроенные функции Python написаны на коде Python (!), IIRC имеет несколько ограничений, связанных с типами начальной загрузки, но у вас есть доступ ко всему, что может переводить Pythonium в совместимый режим. Взгляните на https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master
Чтение JS-кода, сгенерированного с помощью pythonium-совместимого, можно понять, но карты источников очень помогут.
Ценный совет, который я могу дать вам в свете этого опыта, - это старые добрые пердуны:
Только с режимом Python Veloce, я очень счастлив! Но по пути я обнаружил, что то, что я действительно искал, - это освобождение меня и других от Javascript, но, что более важно, возможность создавать комфортным способом. Это привело меня к Scheme, DSL, Models и, в конечном итоге, к моделям, специфичным для предметной области (см. Http://dsmforum.org/ ).
О чем ответ Ира Бакстер:
Оценки совершенно бесполезны. У меня было около 6 месяцев свободного времени как для PythonJS, так и для Pythonium. Так что от 6 месяцев полной занятости я могу ожидать большего. Я думаю, все мы знаем, что 100 человеко-лет в контексте предприятия могут означать и вовсе не означать ...
Когда кто-то говорит, что что-то сложно или чаще невозможно, я отвечаю, что «требуется только время, чтобы найти решение проблемы, которая невозможна», в противном случае сказал, что нет ничего невозможного, кроме случаев, когда это доказано в данном случае математическим доказательством ...
Если не доказано, что это невозможно, остается место для воображения:
и
или
Это не просто оптимистическое мышление. Когда я начинал Python-> Javascript, все говорили, что это невозможно. PyPy невозможно. Метаклассы слишком сложные. и т. д. Я думаю, что единственная революция, которая привносит PyPy в бумагу Scheme-> C (которой 25 лет), - это автоматическая генерация JIT (на основе подсказок, написанных в интерпретаторе RPython, я думаю).
Большинство людей, которые говорят, что что-то «сложно» или «невозможно», не приводят причин. C ++ сложно разобрать? Я знаю это, но они (бесплатные) парсеры C ++. Зло в деталях? Я знаю это. Сказать, что это невозможно в одиночку, бесполезно. Это даже хуже, чем «бесполезно», это обескураживает, и некоторые люди хотят отговорить других. Я слышал об этом вопросе через /programming/22621164/how-to-automatically-generate-a-parser-code-to-code-translator-from-a-corpus .
Что было бы для вас совершенством ? Так вы определяете следующую цель и, возможно, достигнете общей цели.
Я не вижу шаблонов, которые нельзя было бы перевести с одного языка на другой хотя бы неидеально. Поскольку возможен перевод с одного языка на другой, вам лучше сначала сделать это. Поскольку, я думаю, согласно http://en.wikipedia.org/wiki/Graph_isomorphism_problem , перевод между двумя компьютерными языками - это дерево или изоморфизм DAG. Даже если мы уже знаем, что они оба завершены по Тьюрингу, так что ...
Framework-> Framework, который я лучше визуализирую как перевод API-> API, может быть тем, что вы могли бы иметь в виду как способ улучшить сгенерированный код. Например: Пролог как очень специфический синтаксис, но все же вы можете выполнять Пролог как вычисление, описывая тот же граф в Python ... Если бы я должен был реализовать переводчик Пролога в Python, я бы не реализовал унификацию в Python, а в библиотеке C и пришел с "синтаксисом Python", который очень удобен для чтения Pythonist. В конце концов, синтаксис - это всего лишь «картина», которой мы придаем смысл (поэтому я и начал схему). Зло в деталях языка, и я не говорю о синтаксисе. Понятия, которые используются в языке getattributeкрючок (вы можете жить и без него), но с необходимыми функциями виртуальной машины, такими как оптимизация хвостовой рекурсии, может быть трудно справиться. Вам все равно, если исходная программа не использует хвостовую рекурсию, и даже если на целевом языке нет хвостовой рекурсии, вы можете эмулировать ее с помощью гринлетов / цикла событий.
Для целевого и исходного языков ищите:
Из этого выйдет:
Вы также, вероятно, сможете узнать, что будет преобразовано в быстрый и медленный код.
Также есть вопрос о stdlib или любой другой библиотеке, но нет четкого ответа, это зависит от ваших целей.
Идиоматический код или читаемый сгенерированный код также имеют решения ...
Ориентация на такую платформу, как PHP, намного проще, чем на браузеры, поскольку вы можете обеспечить C-реализацию медленного и / или критического пути.
Учитывая, что ваш первый проект - это перевод Python на PHP, по крайней мере, для подмножества PHP3, о котором я знаю, настройка veloce.py - ваш лучший выбор. Если вы можете реализовать veloce.py для PHP, то, вероятно, вы сможете запустить соответствующий режим ... Также, если вы можете перевести PHP в подмножество PHP, которое вы можете сгенерировать с помощью php_veloce.py, это означает, что вы можете перевести PHP в подмножество Python, которое может использовать veloce.py, что означает, что вы можете перевести PHP в Javascript. Просто говорю...
Вы также можете взглянуть на эти библиотеки:
Также вас может заинтересовать это сообщение в блоге (и комментарии): https://www.rfk.id.au/blog/entry/pypy-js-poc-jit/
источник
Вы можете взглянуть на компилятор Vala , который переводит Vala (язык, подобный C #) на C.
источник