Spec-Zone.ru › Python 3.8

parser — Доступ к синтаксическим деревьям Python

Модуль parser предоставляет интерфейс к внутреннему парсеру и компилятору байткода Python. Основное назначение этого интерфейса — позволить коду Python редактировать синтаксическое дерево выражения Python и создавать исполняемый код из него. Это лучше, чем пытаться разобрать и изменить фрагмент произвольного кода Python как строку, потому что разбор выполняется аналогично формированию кода приложения. Также это быстрее.

Примечание

Начиная с Python 2.5, гораздо удобнее работать на стадии генерации и компиляции абстрактного синтаксического дерева (AST), используя модуль ast.

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

Наиболее важно, что требуется хорошее понимание грамматики Python, обрабатываемой внутренним парсером. Для получения полной информации о синтаксисе языка обратитесь к Справочнику по языку Python. Сам парсер создается из спецификации грамматики, определенной в файле Grammar/Grammar в стандартном дистрибутиве Python. Синтаксические деревья, хранящиеся в объектах ST, созданных этим модулем, являются фактическим выходом внутреннего парсера при создании функций expr() или suite(), описанных ниже. Объекты ST, созданные функцией sequence2st(), точно имитируют эти структуры. Имейте в виду, что значения последовательностей, которые считаются «правильными», будут различаться в разных версиях Python по мере пересмотра формальной грамматики языка. Однако перенесение кода из одной версии Python в другую в виде исходного текста всегда позволит создать правильные синтаксические деревья в целевой версии, с единственным ограничением, что миграция на более старую версию интерпретатора не будет поддерживать более новые конструкции языка. Синтаксические деревья обычно несовместимы между различными версиями, хотя исходный код обычно совместим с дальнейшим развитием в рамках одной основной серии выпусков.

Каждый элемент последовательностей, возвращаемых функциями st2list() или st2tuple(), имеет простую форму. Последовательности, представляющие нетерминальные элементы в грамматике, всегда имеют длину больше единицы. Первый элемент — целое число, которое идентифицирует производство в грамматике. Эти числа имеют символические имена в заголовочном файле C Include/graminit.h и модуле Python symbol. Каждый дополнительный элемент последовательности представляет собой компонент производства, распознанный в входной строке: это всегда последовательности, имеющие такую же форму, как и родительская последовательность. Важный аспект этой структуры, который следует отметить, заключается в том, что ключевые слова, используемые для идентификации типа узла-родителя, такие как ключевое слово if в if_stmt, включены в дерево узлов без какого-либо специального обращения. Например, ключевое слово if представлено кортежем (1, 'if'), где 1 — числовое значение, связанное со всеми NAME маркерами, включая имена переменных и функций, определённые пользователем. В альтернативной форме, возвращаемой при запросе информации о номере строки, тот же маркер может быть представлен как (1, 'if', 12), где 12 представляет собой номер строки, в которой был найден терминальный символ.

Терминальные элементы представляются аналогично, но без дочерних элементов и с добавлением идентифицированного исходного текста. Пример с ключевым словом if выше является представительным. Различные типы терминальных символов определены в заголовочном файле C Include/token.h и модуле Python token.

Объекты ST не обязаны поддерживать функциональность этого модуля, но предоставляются для трёх целей: для возможности приложения амортизировать стоимость обработки сложных синтаксических деревьев, для обеспечения представления синтаксического дерева, сохраняющего объём памяти по сравнению с представлением Python в виде списка или кортежа, и для упрощения создания дополнительных модулей на C, манипулирующих синтаксическими деревьями. В Python может быть создан простой класс «обёртки», чтобы скрыть использование объектов ST.

Модуль parser определяет функции для нескольких различных целей. Наиболее важные цели — создание объектов ST и преобразование объектов ST в другие представления, такие как синтаксические деревья и объекты скомпилированного кода, но также есть функции, предназначенные для запроса типа синтаксического дерева, представленного объектом ST.

См. также

Module symbol

Полезные константы, представляющие внутренние узлы синтаксического дерева.

Module token

Полезные константы, представляющие листья синтаксического дерева, и функции для проверки значений узлов.

Создание объектов ST

Объекты ST могут быть созданы из исходного кода или из синтаксического дерева. При создании объекта ST из исходного кода используются разные функции для создания форм 'eval' и 'exec'.

parser.expr(source)

Функция expr() разбирает параметр source так, как будто он является вводом для compile(source, 'file.py', 'eval'). Если разбор успешен, создаётся объект ST для хранения внутреннего представления синтаксического дерева, в противном случае генерируется соответствующее исключение.

parser.suite(source)

Функция suite() разбирает параметр source так, как будто он является вводом для compile(source, 'file.py', 'exec'). Если разбор успешен, создаётся объект ST для хранения внутреннего представления синтаксического дерева, в противном случае генерируется соответствующее исключение.

parser.sequence2st(sequence)

Эта функция принимает синтаксическое дерево, представленное как последовательность, и строит внутреннее представление, если возможно. Если она может проверить, что дерево соответствует грамматике Python, и все узлы являются допустимыми типами узлов в текущей версии Python, из внутреннего представления создаётся объект ST и возвращается вызывающей стороне. Если возникла проблема при создании внутреннего представления или если дерево не может быть проверено, генерируется исключение ParserError. Не следует предполагать, что объект ST, созданный таким образом, будет корректно скомпилирован; обычные исключения, возникающие при компиляции, могут всё ещё быть инициированы, когда объект ST передаётся в compilest(). Это может указывать на проблемы, не связанные с синтаксисом (такие как исключение MemoryError), но также может быть связано с конструкциями, такими как результат разбора del f(0), которые уходят за пределы парсера Python, но проверяются компилятором байткода.

Последовательности, представляющие терминальные токены, могут быть представлены как списки из двух элементов вида (1, 'name') или как списки из трёх элементов вида (1, 'name', 56). Если третий элемент присутствует, он предполагается допустимым номером строки. Номер строки может быть указан для любого подмножества терминальных символов во входном дереве.

parser.tuple2st(sequence)

Эта функция идентична sequence2st(). Этот входной пункт поддерживается для обратной совместимости.

Преобразование объектов ST

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

parser.st2list(st, line_info=False, col_info=False)

Эта функция принимает объект ST от вызывающей стороны в st и возвращает список Python, представляющий эквивалентное дерево разбора. Результирующее представление в виде списка может использоваться для проверки или создания нового дерева разбора в виде списка. Эта функция не завершается ошибкой, пока доступна память для построения представления в виде списка. Если дерево разбора будет использоваться только для проверки, st2tuple() следует использовать вместо него для уменьшения использования памяти и фрагментации. Когда необходимо представление в виде списка, эта функция значительно быстрее, чем получение представления в виде кортежа и преобразование его в вложенные списки.

Если line_info имеет значение true, информация о номерах строк будет включена для всех терминальных токенов в качестве третьего элемента списка, представляющего токен. Обратите внимание, что указанный номер строки соответствует строке, в которой токен заканчивается. Эта информация опущена, если флаг имеет значение false или опущен.

parser.st2tuple(st, line_info=False, col_info=False)

Эта функция принимает объект ST от вызывающей стороны в st и возвращает кортеж Python, представляющий эквивалентное дерево разбора. Кроме возвращения кортежа вместо списка, эта функция идентична st2list().

Если line_info имеет значение true, информация о номерах строк будет включена для всех терминальных токенов в качестве третьего элемента списка, представляющего токен. Эта информация опущена, если флаг имеет значение false или опущен.

parser.compilest(st, filename='<syntax-tree>')

Компилятор байткода Python может быть вызван для объекта ST для создания объектов кода, которые могут быть использованы в качестве части вызова встроенных функций exec() или eval(). Эта функция предоставляет интерфейс к компилятору, передавая внутреннее дерево разбора из st в анализатор, используя имя файла исходного кода, указанное параметром filename. Значение по умолчанию, предоставляемое для filename, указывает, что исходный код был объектом ST.

Компиляция объекта ST может привести к исключениям, связанным с компиляцией; примером является SyntaxError, вызванный деревом разбора для del f(0): это утверждение считается законным в формальной грамматике Python, но не является законной конструкцией языка. SyntaxError, вызываемый в этом случае, фактически генерируется компилятором байткода Python, поэтому он может быть вызван на этом этапе модулем parser. Большинство причин сбоя компиляции могут быть диагностированы программно путем проверки дерева разбора.

Запросы к объектам ST

Предоставлены две функции, которые позволяют приложению определить, был ли объект ST создан как выражение или набор инструкций. Ни одна из этих функций не может использоваться для определения того, был ли объект ST создан из исходного кода с помощью expr() или suite() или из дерева разбора с помощью sequence2st().

parser.isexpr(st)

Когда st представляет собой форму 'eval', эта функция возвращает True, в противном случае она возвращает False. Это полезно, так как объекты кода обычно не могут быть запрошены для этой информации с помощью существующих встроенных функций. Обратите внимание, что объекты кода, созданные функцией compilest(), также не могут быть запрошены таким образом и идентичны объектам кода, созданным встроенной функцией compile().

parser.issuite(st)

Эта функция дублирует функцию isexpr(), сообщая, представляет ли объект ST форму 'exec', обычно называемую «набором инструкций». Не следует полагать, что эта функция эквивалентна not isexpr(st), так как в будущем могут быть добавлены дополнительные фрагменты синтаксиса.

Исключения и обработка ошибок

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

exception parser.ParserError

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

Обратите внимание, что функции compilest(), expr() и suite() могут генерировать исключения, которые обычно генерируются процессом разбора и компиляции. К ним относятся встроенные исключения MemoryError, OverflowError, SyntaxError и SystemError. В этих случаях эти исключения сохраняют все значение, обычно с ними ассоциированное. Обратитесь к описаниям каждой функции для получения подробной информации.

Объекты ST

Поддерживаются упорядоченные и сравнения на равенство между объектами ST. Также поддерживается сериализация объектов ST (с помощью модуля pickle).

parser.STType

Тип объектов, возвращаемых функциями expr(), suite() и sequence2st().

Объекты ST имеют следующие методы:

ST.compile(filename='<syntax-tree>')

То же, что и compilest(st, filename).

ST.isexpr()

То же, что и isexpr(st).

ST.issuite()

То же, что и issuite(st).

ST.tolist(line_info=False, col_info=False)

То же, что и st2list(st, line_info, col_info).

ST.totuple(line_info=False, col_info=False)

То же, что и st2tuple(st, line_info, col_info).

Пример: Эмуляция compile()

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

>>> code = compile('a + 5', 'file.py', 'eval')
>>> a = 5
>>> eval(code)
10

Эквивалентная операция с использованием модуля parser несколько длиннее и позволяет сохранить промежуточное внутреннее дерево разбора в качестве объекта ST:

>>> import parser
>>> st = parser.expr('a + 5')
>>> code = st.compile('file.py')
>>> a = 5
>>> eval(code)
10

Приложение, которому нужны как объекты ST, так и объекты кода, может упаковать этот код в готовые функции:

import parser

def load_suite(source_string):
    st = parser.suite(source_string)
    return st, st.compile()

def load_expression(source_string):
    st = parser.expr(source_string)
    return st, st.compile()

© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.8/library/parser.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API