php шаблонизатор - Какие шаблоны я мог бы использовать в коде, чтобы упростить перевод на другой язык программирования?




3 Answers

Я создавал инструменты (DMS Software Reengineering Toolkit) для выполнения манипуляций с универсальными программами (с переводом на язык, являющимся особым случаем) с 1995 года, при поддержке сильной команды компьютерных ученых. DMS обеспечивает общий синтаксический анализ, построение АСТ, таблицы символов, анализ управления и потока данных, применение правил перевода, регенерацию исходного текста с комментариями и т. Д., Все параметры которого определяются явными определениями компьютерных языков.

Объем оборудования, который вам нужен для этого, огромен (особенно если вы хотите иметь возможность сделать это для нескольких языков в общем виде), а затем вам понадобятся надежные парсеры для языков с ненадежными определениями (PHP - прекрасный пример этого ).

Нет ничего плохого в том, что вы думаете о создании переводчика на языке или его попытке, но я думаю, что вы найдете это гораздо более сложной задачей для реальных языков, чем вы ожидаете. У нас есть около 100 человеко-лет, вложенных в просто DMS, а еще 6-12 месяцев в каждое «надежное» определение языка (включая ту, которую мы мучительно создаем для PHP), и многое другое для неприятных языков, таких как C ++. Это будет «адский опыт»; это было для нас. (Вы можете найти раздел технических документов на вышеуказанном веб-сайте, интересный, чтобы начать с начала обучения).

Люди часто пытаются создать какой-то обобщенный механизм, начиная с какой-то технологии, с которой они знакомы, что делает часть работы. (Атрибуты Python - отличный пример). Хорошая новость заключается в том, что часть работы завершена. Плохая новость заключается в том, что в машинах есть встроенные в него предположения, большинство из которых вы не обнаружите, пока не попытаетесь бороться с чем-то другим. В этот момент вы узнаете, что оборудование подключено к тому, чтобы делать то, что оно изначально делает, и действительно будет действительно противостоять вашей попытке заставить его сделать что-то еще. (Я подозреваю, что попытка получить Python AST для моделирования PHP будет очень весело).

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

Многие люди также ошибаются, полагая, что, если они смогут разобрать (и, возможно, получить АСТ), они на пути к чему-то сложному. Одним из трудных уроков является то, что вам нужны таблички с символами и анализ потока для хорошего анализа или преобразования программ. АСТ необходимы, но недостаточно. Именно по этой причине книга компилятора Aho & Ullman не останавливается на главе 2. (OP имеет это право в том, что он планирует построить дополнительные машины за пределами AST). Подробнее об этой теме см. « Жизнь после анализа» .

Замечание о том, что «мне не нужен совершенный перевод», вызывает беспокойство. То, что делают слабые переводчики, составляет «легкий» 80% кода, оставляя трудным 20% делать вручную. Если приложение, которое вы намерены преобразовать, довольно мало, и вы только намерены его конвертировать один раз, тогда 20% в порядке. Если вы хотите преобразовать многие приложения (или даже те же, что и с незначительными изменениями с течением времени), это не приятно. Если вы попытаетесь преобразовать 100K SLOC, тогда 20% - это 20 000 оригинальных строк кода, которые трудно перевести, понять и изменить в контексте еще 80 000 строк переведенной программы, которые вы уже не понимаете. Это требует огромных усилий. На уровне миллионной линии это практически невозможно на практике. (Удивительно, что есть люди, которые не доверяют автоматическим инструментам и настаивают на том, чтобы перевести миллионы линейных систем вручную, это еще сложнее, и они обычно обнаруживают мучительно длительные задержки, высокие затраты и часто прямые сбои.)

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

Другим ключевым соображением является размер кода для перевода. Требуется много энергии для создания надежного переводчика, даже с хорошими инструментами. Хотя кажется, что сексуально и здорово создавать переводчика вместо простого ручного преобразования, для небольших базовых кодов (например, до примерно 100 тыс. SLOC в нашем опыте) экономика просто не оправдывает его. Никто не любит этот ответ, но если вам действительно нужно перевести только 10K SLOC кода, вам, вероятно, лучше просто кусать пулю и делать это. И да, это больно.

Я считаю, что наши инструменты очень хороши (но тогда я довольно предвзятый). И еще очень сложно построить хорошего переводчика; это занимает около 1,5-2 человеко-лет, и мы знаем, как использовать наши инструменты. Разница в том, что с помощью этого большого механизма мы succeed значительно чаще, чем мы терпим неудачу.

уроки лучший

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

  • Это ориентировано на веб-разработку. Оригинальный и целевой код будет сидеть поверх фреймворков (которые мне также придется писать). Эти рамки будут охватывать шаблон проектирования MVC и следовать строгим правилам кодирования. Это должно сделать перевод несколько проще.

  • Я также рассматриваю IOC и инъекции зависимостей, поскольку они могут облегчить процесс перевода и уменьшить вероятность ошибок.

  • Я буду использовать модуль парсера Python, который позволяет мне играть с абстрактным деревом синтаксиса. По-видимому, ближе всего к PHP можно token_get_all() , что является началом.

  • С этого момента я могу построить AST, таблицы символов и поток управления.

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

Прежде чем спросить: «Что, черт возьми, в этом смысл?» Ответ будет ... Это будет интересный опыт обучения. Если у вас есть какие-либо сведения о том, как сделать это менее сложным, сообщите мне.

РЕДАКТИРОВАТЬ:

Мне больше интересно узнать, какие шаблоны я мог бы применять для кода, чтобы упростить перевод (т.е. IoC, SOA?) Кода, чем как сделать перевод.




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

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

Например:

word = 'This is not a word'
print word[::-2]

берет много кода на C ++, чтобы дублировать (хорошо, хорошо, вы можете сделать это довольно коротко с некоторыми циклами, но все же).

Наверное, это немного в стороне.

Вы когда-нибудь писали токенизатор / парсер, основанный на грамматике языка? Вероятно, вам захочется узнать, как это сделать, если вы этого не сделали, потому что это основная часть этого проекта. То, что я хотел бы сделать, это получить базовый синтаксис Turing - что-то довольно похожее на bytecode Python. Затем вы создаете лексер / парсер, который принимает грамматику языка (возможно, используя BNF ) и на основе грамматики компилирует язык на ваш промежуточный язык. Тогда то, что вы хотите сделать, это сделать наоборот - создать парсер с вашего языка в целевые языки на основе грамматики.

Наиболее очевидной проблемой, которую я вижу, является то, что сначала вы, вероятно, создадите ужасно неэффективный код, особенно на более мощных * языках, таких как Python.

Но если вы сделаете это так, то вы, вероятно, сможете найти способы оптимизации вывода по мере продвижения. Обобщить:

  • читать грамматику
  • компилировать программу в промежуточный (но также полный)
  • компилировать промежуточную программу на конечный язык (на основе предоставленной грамматики)
  • ...?
  • Прибыль! (?)

* мощным я имею в виду, что это занимает 4 строки:

myinput = raw_input("Enter something: ")
print myinput.replace('a', 'A')
print sum(ord(c) for c in myinput)
print myinput[::-1]

Покажите мне другой язык, который может сделать что-то подобное в 4 строках, и я покажу вам язык, столь же мощный, как 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, лучшее, что существует, это Single inhertance + mixins, и я не уверен, что они справляются с наложением алмазов. Вид похож на Skulpt, но без google clojure.

  • Я попытался с помощью Google clojure, как и Skulpt (компилятор), вместо того, чтобы фактически читать код Skulpt #fail. В любом случае из-за объектной системы на основе прототипа JS все еще невозможно. Создание привязки было очень сложным, вам нужно написать JavaScript и много шаблонов (см. https://github.com/skulpt/skulpt/issues/50 где я - призрак). В то время не было четкого способа интеграции привязки в систему сборки. Я думаю, что Skulpt - это библиотека, и вам просто нужно включить ваши .py-файлы в html, который должен быть выполнен, и не требуется этап компиляции, который должен выполнить разработчик.

  • Пробовал pyjaco (компилятор), но создавал привязки (вызывая код Javascript из кода Python), было очень сложно, было слишком много шаблонов, чтобы создавать каждый раз. Теперь я думаю, что пияко - это тот, который ближе к Pythonium. pyjaco написан на Python (ast.parse тоже), но много написано на JavaScript и использует прототип наследования.

Мне никогда не удалось запустить Pajamas #fail и никогда не пытались снова прочитать код #fail. Но, на мой взгляд, в пижаме делались API-> API tranlation (или framework для фреймворка), а не Python для перевода JavaScript. Структура JavaScript использует данные, которые уже находятся на странице или данные с сервера. Код Python - только «сантехника». После этого я обнаружил, что пижама - настоящий переводчик python-> js.

Тем не менее, я думаю, что возможно преобразование API-> API (или framework-> framework), и это в основном то, что я делаю в Pythonium, но на более низком уровне. Вероятно, пижама использует тот же алгоритм, что и Pythonium ...

Затем я обнаружил, что brython полностью написан в Javascript, таком как Skulpt, нет необходимости в компиляции и много пуха ... но написан на JavaScript.

Начиная с начальной строки, написанной в ходе этого проекта, я знал о PyPy, даже бэкэнде JavaScript для PyPy. Да, вы можете, если найдете его, напрямую сгенерировать интерпретатор Python в JavaScript из PyPy. Люди говорят, что это была катастрофа. Я не читал, почему. Но я думаю, что причина в том, что промежуточный язык, который они используют для реализации интерпретатора, RPython, является подмножеством Python, предназначенным для перевода на C (и, возможно, asm). Ира Бакстер говорит, что вы всегда делаете предположения, когда вы что-то строите, и, возможно, вы точно настроите ее на лучшее, что она должна делать в случае перевода PyPy: Python-> C. Эти предположения могут быть неактуальными в другом контексте, хуже того, что они могут вызывать накладные расходы, иначе прямой перевод, скорее всего, всегда будет лучше.

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

Я начал PythonJS с идеей собрать подмножество Python, которое я мог бы легко перевести на JavaScript. Сначала я даже не потрудился внедрить систему OO из-за прошлого опыта. Подмножество Python, которое я достиг, чтобы перевести на JavaScript:

  • функция с полными параметрами семантики как в определении, так и при вызове. Это та часть, которой я больше всего горжусь.
  • в то время как / если / Элиф / другое
  • Типы Python были преобразованы в типы JavaScript (нет типов python любого типа)
  • for может выполнять итерацию только по массивам Javascript (для массива)
  • Прозрачный доступ к JavaScript: если вы пишете Array в коде Python, он будет переведен в Array в javascript. Это самое большое достижение в плане удобства использования над конкурентами.
  • Вы можете передать функцию, определенную в источнике Python, на функции javascript. Аргументы по умолчанию будут учтены.
  • Он добавляет специальную функцию new, которая переводится на новый JavaScript: например, новый (Python) (1, 2, спам, «яйцо») переводится на «новый Python (1, 2, спам,« яйцо »).
  • «var» автоматически обрабатывается переводчиком. (очень хороший вывод от Бретта (PythonJS contributor).
  • ключевое слово global
  • укупорочные
  • лямбды
  • список понятий
  • импорт поддерживается через requirejs
  • однонамерное наследование + mixin через classyjs

Это кажется очень много, но на самом деле очень узким по сравнению с полной размытой семантикой 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 или что-нибудь еще.
  • метод разрешения разрешения: даже с алгоритмом, написанным на Python, перевод его на совместимый с Python Veloce код был большим делом.
  • getattributre : фактический алгоритм разрешения getattribute является довольно сложным и по-прежнему не поддерживает дескрипторы данных
  • класс metaclass на основе: я знаю, где подключить код, но все же ...
  • last bu не менее: some_callable (...) всегда транслируется на «call (some_callable)». AFAIK переводчик не использует вывода вообще, поэтому каждый раз, когда вы делаете вызов, вам нужно проверить, какой из объектов он должен назвать так, как он должен быть вызван.

Эта часть учтена в 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 в моем случае, по крайней мере, может быть улучшением производительности, поскольку я когда-нибудь проверяю содержимое блока перед созданием связанного с ним кода, например:

  • var / global: чтобы иметь возможность var что-то, я должен знать, что мне нужно, а не var. Вместо того, чтобы генерировать отслеживание блоков, какая переменная создается в заданном блоке и вставляя ее поверх сгенерированного функционального блока, я просто ищу назначение перераспределения переменных при входе в блок до фактического посещения дочернего узла для генерации связанного кода.
  • yield, генераторы пока еще имеют специальный синтаксис в JS, поэтому мне нужно знать, какая функция Python является генератором, когда я хочу написать «var my_generator = function»,

Поэтому я не посещаю каждый узел один раз для каждой фазы перевода.

Общий процесс может быть описан как:

Python source code -> Python ast -> Python source code compatible with Veloce mode -> Python ast -> JavaScript source code

Встроенные Python написаны в коде Python (!), IIRC существует несколько ограничений, связанных с типами бутстрапинга, но у вас есть доступ ко всему, что может перевести Pythonium в совместимый режим. Посмотрите на https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master

Чтение JS-кода, сгенерированного с помощью pythonium-совместимого, можно понять, но исходные карты значительно помогут.

Ценный совет, который я могу дать вам в свете этого опыта, - это добрые старые пучки:

  • широко рассматривают предмет как в литературе, так и в существующих проектах, закрытых или свободных. Когда я рассмотрел различные существующие проекты, я должен был дать ему больше времени и мотивации.
  • задавать вопросы! Если бы я заранее знал, что бэкэнд PyPy бесполезен из-за накладных расходов из-за семантического несоответствия C / Javascript. Возможно, у меня была идея идеи Pythonium до 6 месяцев назад, может быть, 3 года назад.
  • знать, что вы хотите сделать, иметь цель. Для этого проекта у меня были разные цели: немного оценить javascript, узнать больше о Python и уметь писать код Python, который будет запускаться в браузере (подробнее и ниже).
  • неудача - это опыт
  • небольшой шаг - это шаг
  • начинать с малого
  • большая мечта
  • делать демонстрации
  • повторять

Только в режиме Python Veloce я очень счастлив! Но по пути я обнаружил, что то, что я действительно искал, освобождало меня и других от Javascript, но, что более важно, было способно создать в удобном виде. Это привело меня к схемам, DSL, моделям и, в конечном итоге, к конкретным моделям (см. http://dsmforum.org/ ).

О том, что ответ Ира Бакстера:

Оценки вообще не помогают. Я взял у меня более или менее 6 месяцев свободного времени для PythonJS и Pythonium. Поэтому я могу ожидать большего от полного времени 6 месяцев. Я думаю, мы все знаем, что 100 человеко-года в контексте предприятия могут означать и вовсе не означать ...

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

Если это не представляется невозможным, то это оставляет пространство для воображения:

  • найти доказательство, доказывающее, что это невозможно

а также

  • Если это невозможно, может быть проблема «хуже», которая может иметь решение.

или

  • если это не невозможно, найти решение

Это не просто оптимистическое мышление. Когда я начал Python-> Javascript, все говорили, что это невозможно. PyPy невозможно. Метаклассы слишком сложны. и т. д. Я думаю, что единственная революция, которая приносит PyPy над документом Scheme-> C (которому составляет 25 лет), - это некоторая автоматическая генерация JIT (основанные подсказки, написанные в интерпретаторе RPython, я думаю).

Большинство людей, которые говорят, что вещь «трудная» или «невозможная», не приводят причин. C ++ сложно разобрать? Я знаю, что они все еще являются (свободным) парсером C ++. Зло в деталях? Я знаю это. Говорить, что это невозможно в одиночку, это не полезно, это даже хуже, чем «не полезно», это обескураживает, а некоторые люди препятствуют другим. Я слышал об этом вопросе через https://.com/questions/22621164/how-to-automatically-generate-a-parser-code-to-code-translator-from-a-corpus .

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

Мне больше интересно узнать, какие шаблоны я мог бы применять для кода, чтобы упростить перевод (т.е. IoC, SOA?) Кода, чем как сделать перевод.

Я не вижу шаблонов, которые не могут быть переведены с одного языка на другой, по крайней мере, менее совершенным способом. Поскольку языковой перевод возможен, вам лучше ориентироваться на этом. Поскольку, я думаю, согласно http://en.wikipedia.org/wiki/Graph_isomorphism_problem , перевод между двумя компьютерными языками является изоморфизмом дерева или DAG. Даже если мы уже знаем, что они оба завершены, так ...

Framework-> Framework, который я лучше визуализирую как API-> API-перевод, может все же быть тем, что вы можете иметь в виду как способ улучшить сгенерированный код. Например: Prolog как очень специфический синтаксис, но все же вы можете делать Prolog как вычисление, описывая один и тот же граф в Python ... Если бы я должен был реализовать Prolog для Python-переводчика, я бы не реализовал унификацию в Python, а в библиотеке C и пришел с синтаксисом Python, который очень читается для Pythonist. В конце концов, синтаксис - это только «живопись», для которой мы даем смысл (вот почему я начал схему). Зло в деталях языка, и я не говорю о синтаксисе. Концепции, которые используются в языке getattribute hook (вы можете жить без него), но требуемые функции VM, такие как оптимизация хвостовой рекурсии, могут быть трудными. Вас не волнует, если исходная программа не использует хвостовую рекурсию, и даже если на целевом языке нет рекурсии хвоста, вы можете эмулировать ее с помощью greenlets / loop событий.

Для целевых и исходных языков найдите:

  • Большие и конкретные идеи
  • Крошечные и общие общие идеи

Из этого выйдут:

  • Вещи, которые легко перевести
  • Вещи, которые трудно перевести

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

Существует также вопрос о 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/




Related

php python compiler-construction coding-style abstract-syntax-tree