Один способ сделать вещи как это состоит в том, чтобы предварительно обработать источник и изменить его, переведя Ваш добавленный оператор в Python. Существуют различные проблемы, которые принесет этот подход, и я не рекомендовал бы его для общего использования, но для экспериментирования с языком или метапрограммирования определенной цели, это может иногда быть полезно.
, Например, позволяет, говорят, что мы хотим представить "myprint" оператор, который вместо того, чтобы печатать на экран вместо этого регистрируется в определенный файл. т.е.:
myprint "This gets logged to file"
было бы эквивалентно [1 112]
print >>open('/tmp/logfile.txt','a'), "This gets logged to file"
существуют различные варианты относительно того, как сделать замену, от regex замены до генерации AST, к записи Вашего собственного синтаксического анализатора в зависимости от того, как близко Ваш синтаксис соответствует существующему Python. Хороший промежуточный подход должен использовать модуль токенизатора. Это должно позволить Вам добавлять новые ключевые слова, управляющие структуры и т.д. при интерпретации источника так же к интерпретатору Python, таким образом предотвращении, чтобы сырая нефть поломки regex решения вызвала бы. Для вышеупомянутого "myprint", Вы могли записать следующий код преобразования:
import tokenize
LOGFILE = '/tmp/log.txt'
def translate(readline):
for type, name,_,_,_ in tokenize.generate_tokens(readline):
if type ==tokenize.NAME and name =='myprint':
yield tokenize.NAME, 'print'
yield tokenize.OP, '>>'
yield tokenize.NAME, "open"
yield tokenize.OP, "("
yield tokenize.STRING, repr(LOGFILE)
yield tokenize.OP, ","
yield tokenize.STRING, "'a'"
yield tokenize.OP, ")"
yield tokenize.OP, ","
else:
yield type,name
(Это действительно делает myprint эффективно ключевым словом, таким образом используйте, поскольку переменная в другом месте, вероятно, вызовет проблемы)
, проблема тогда состоит в том, как использовать его так, чтобы Ваш код был применим из Python. Один путь состоял бы в том, чтобы просто записать Вашу собственную функцию импорта и использовать ее для загрузки кода, записанного на пользовательском языке. т.е.:
import new
def myimport(filename):
mod = new.module(filename)
f=open(filename)
data = tokenize.untokenize(translate(f.readline))
exec data in mod.__dict__
return mod
Это требует, чтобы Вы обработали свой специализированный код по-другому по сравнению с нормальными модулями Python как бы то ни было. т.е." some_mod = myimport("some_mod.py")
", а не" import some_mod
"
Другой довольно аккуратный (хотя hacky) решение состоит в том, чтобы создать пользовательское кодирование (См. PEP 263) как этот демонстрирует рецепт. Вы могли реализовать это как:
import codecs, cStringIO, encodings
from encodings import utf_8
class StreamReader(utf_8.StreamReader):
def __init__(self, *args, **kwargs):
codecs.StreamReader.__init__(self, *args, **kwargs)
data = tokenize.untokenize(translate(self.stream.readline))
self.stream = cStringIO.StringIO(data)
def search_function(s):
if s!='mylang': return None
utf8=encodings.search_function('utf8') # Assume utf8 encoding
return codecs.CodecInfo(
name='mylang',
encode = utf8.encode,
decode = utf8.decode,
incrementalencoder=utf8.incrementalencoder,
incrementaldecoder=utf8.incrementaldecoder,
streamreader=StreamReader,
streamwriter=utf8.streamwriter)
codecs.register(search_function)
Теперь после того, как этот код выполняется (например, Вы могли поместить его в свой .pythonrc или site.py), любой код, запускающийся с комментария "# кодирование: mylang" будет автоматически переведен через вышеупомянутый шаг предварительной обработки. например,
# coding: mylang
myprint "this gets logged to file"
for i in range(10):
myprint "so does this : ", i, "times"
myprint ("works fine" "with arbitrary" + " syntax"
"and line continuations")
Протесты:
существуют проблемы к подходу препроцессора, поскольку Вы, вероятно, будете знакомы с тем, если Вы работали с препроцессором C. Основной отлаживает. Весь Python видит, предварительно обработанный файл, что означает, что текст, распечатанный в отслеживании стека и т.д., будет относиться к этому. При выполнении значительного перевода это может очень отличаться от исходного текста. Пример выше не изменяет номера строки и т.д., так не будет слишком отличаться, но чем больше Вы изменяете его, тем тяжелее он должен будет выяснить.
Да, в некоторой степени это возможно. Существует модуль там, который использует sys.settrace()
для реализации goto
и comefrom
"ключевые слова":
from goto import goto, label
for i in range(1, 10):
for j in range(1, 20):
print i, j
if j == 3:
goto .end # breaking out from nested loop
label .end
print "Finished"
За исключением изменения и перекомпиляции исходного кода (который возможны с открытым исходным кодом), изменяя основной язык не действительно возможно.
Даже при перекомпиляции источника это не был бы Python, просто взломанная измененная версия, в которую необходимо очень бояться представлять ошибки.
Однако я не уверен, почему Вы хотели бы. Объектно-ориентированные функции Python делают довольно простым достигнуть подобных результатов с языком как есть.
Общий ответ: необходимо предварительно обработать исходные файлы.
более определенный ответ: установка EasyExtend, и проходит следующие шаги
, i) Создают новый langlet (дополнительный язык)
import EasyExtend
EasyExtend.new_langlet("mystmts", prompt = "my> ", source_ext = "mypy")
Без дополнительной спецификации, набор файлов должен быть создан под EasyExtend/langlets/mystmts/.
ii), Открывают mystmts/parsedef/Grammar.ext и добавляют следующие строки
small_stmt: (expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt |
import_stmt | global_stmt | exec_stmt | assert_stmt | my_stmt )
my_stmt: 'mystatement' expr
, Это достаточно для определения синтаксиса нового оператора. small_stmt нетерминальной является часть грамматики Python, и это - место, где новый оператор сцепляется в. Синтаксический анализатор теперь распознает новый оператор, т.е. исходный файл, содержащий его, будет проанализирован. Компилятор отклонит его хотя, потому что это все еще должно быть преобразовано в действительный Python.
iii), Теперь нужно добавить семантику оператора. Поскольку этот должен отредактировать msytmts/langlet.py и добавить my_stmt посетителя узла.
def call_my_stmt(expression):
"defines behaviour for my_stmt"
print "my stmt called with", expression
class LangletTransformer(Transformer):
@transform
def my_stmt(self, node):
_expr = find_node(node, symbol.expr)
return any_stmt(CST_CallFunc("call_my_stmt", [_expr]))
__publish__ = ["call_my_stmt"]
iv) CD к langlets/mystmts и типу
python run_mystmts.py
Теперь сессия должна быть запущена, и недавно определенный оператор может использоваться:
__________________________________________________________________________________
mystmts
On Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)]
__________________________________________________________________________________
my> mystatement 40+2
my stmt called with 42
Довольно много шагов для прибытия в тривиальный оператор, правильно? Еще нет API, который позволяет, каждый определяет простые вещи, не имея необходимость заботиться о грамматиках. Но EE очень надежен по модулю некоторые ошибки. Таким образом, это - просто вопрос времени, что API появляется, который позволяет программистам определить удобный материал как инфиксные операторы или маленькие операторы, использующие просто удобное программирование OO. Для более сложных вещей как встраивание целых языков в Python посредством создания langlet нет никакого способа обойти полный подход грамматики.
Я нашел руководство по добавлению новых операторов:
https://troeger.eu/files/teaching/pythonvm08lab.pdf
В основном, для добавления новых операторов необходимо отредактировать Python/ast.c
(среди прочего) и перекомпилировать двоичный файл Python.
, В то время как это возможно, не делать. Можно достигнуть почти всего через функции и классы (какая привычка требуют, чтобы люди перекомпилировали Python только для выполнения сценария..)
Возможно сделать это использование EasyExtend:
EasyExtend (EE) является генератором препроцессора и платформой метапрограммирования, записанной в чистом Python и интегрированной с CPython. Основной целью EasyExtend является создание дополнительных языков т.е. добавление пользовательского синтаксиса и семантики к Python.
Не изменяя интерпретатор. Я знаю, что много языков за прошлые несколько лет было описано как "расширяемое", но не в способе, которым Вы описываете. Вы расширяете Python путем добавления функций и классов.
Существует язык на основе Python, названного Logix, с которым Вы CAN делают такие вещи. Это не разрабатывалось некоторое время, но функции, которые Вы попросили , действительно работают с последней версией.
Десять лет назад Вы не могли, и я сомневаюсь, что это изменяется. Однако не случалось так, что трудно для изменения синтаксиса тогда, если Вы были готовы перекомпилировать Python, и я сомневаюсь, что это изменяется, также.