Каков наилучший способ анализа файла скрипта Python в коде C / C ++ - PullRequest
2 голосов
/ 02 января 2011

Я встраиваю python в программу C / C ++.

Я пытаюсь разобрать файл скрипта python из программы C / C ++, разбить файл на «блоки», чтобы каждый «block "является допустимой командой в коде Python .Каждый блок мне нужно положить в std::string.Например:

#PythonScript.py

import math

print "Hello Python"
i = 0;
while (i < 10):
    print "i = " , i;
    i = i + 1;

print "GoodBye Python"

В этом скрипте 5 разных «блоков»:

  • первый - "import math;"
  • второй - "print "Hello Python;"
  • третий - "i = 0;"
  • и четвертый -

    while (i < 10):\n\tprint "i = " , i;\n\ti = i + 1;
    

Мои знания в области Python очень просты, и яне знаком с синтаксисом кода Python.Каков наилучший способ сделать это, есть ли какая-либо функция Python C / C ++ API, которая поддерживает это?


зачем мне это нужно -> для целей графического интерфейса.Моя программа, написанная на C, использует Python для некоторых вычислений.Я запускаю из кода C, используя Python C API, сценарий Python, и мне нужен способ для захвата вывода Python в моей программе.Я ловлю это, и все в порядке, проблема в том, когда скрипт включает пользовательский ввод.Что происходит, так это то, что я записываю вывод Python после завершения скрипта, поэтому, когда в скрипте есть входная команда, я получаю черный экран .... Мне нужно получить все распечатки перед входной командой.

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

Ответы [ 5 ]

4 голосов
/ 02 января 2011

Я понятия не имею, почему вы хотите это сделать, но самый безопасный способ - это позволить самому Python выполнять работу по синтаксическому анализу. Если вы используете Python ранее 2.6, вы можете использовать модуль compiler. Для версии 2.6 и выше используйте встроенную функцию compile и модуль ast. В 3.x у вас есть для их использования, так как модуль compiler был удален.

1 голос
/ 02 января 2011

Если вы хотите выполнить синтаксический анализ, вам следует изучить грамматику Pythons (и, возможно, использовать Bison в качестве генератора синтаксического анализатора)

Спецификации грамматики Python:

1 голос
/ 02 января 2011

Я думаю, что вы пытаетесь выполнить дополнительную работу, потому что есть (по крайней мере) Встраивание Python в другое средство приложения , и вы можете просто выполнить свой скрипт через API Python / C.Мне кажется, вы не хотите писать код интерпретатора Python с нуля, не так ли?

0 голосов
/ 02 января 2011

@ genesiss дал всю необходимую вам информацию.

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

Глядя на Официальную грамматику Python , наиболее близкий элемент синтаксиса к вашему "блоку" будет statement.

statement ::= 
             stmt_list NEWLINE | compound_stmt

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

Также обратите внимание на номер 4 лексической структуры:

За пределамистроковые литералы, символы новой строки (обозначаются NEWLINE ниже) являются значимыми, за исключением случаев, когда

  • Им непосредственно предшествует символ обратной косой черты ("\"), в этом случае обаОбратная косая черта и новая строка (по сути) заменяются пробелом, соединяя две разделяемые ими строки.

  • Они заключены в соответствующие открывающие и закрывающие скобки: "("и") "," ["и"] "или" {"и"} ".В этом случае также символ новой строки обрабатывается как пробел.

Итак, читайте ввод символов char по char, ищите '\', '\ n' и разделители.

Пример кода ниже (просто концептуальный эскиз):

std::string input;
std::string::const_iterator it = input.begin();
std::string::const_iterator itEnd = input.end();

int delim = 0;
bool escape = false;
std::string block;

while (it != itEnd)
{
char c = *it;

switch (c) {
case '\\':
  if (!delim) escape = true;
  break;
case '\n':
  if (!delim && !escape)
    write_block(); // handle contents of the block variable
  escape = false;
  break;
case '(': case '[': case '{':
  ++delim; escape = false;
  break;
case ')': case ']': case '}':
  --delim; escape = false;
  break;
}

block.append(c, 1);
++it;
}

EDITED

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

0 голосов
/ 02 января 2011

Зачем тебе это? Если вы встраиваете Python, вам не нужно анализировать код Python самостоятельно - даже удаленно.

Но чтобы ответить на вопрос: вы можете использовать модуль Python ast (который использует встроенный модуль _ast внутри - я не знаю, можете ли вы использовать его из C). ast.parse("""... your code ...""") дает объект Module, имеющий атрибут body, представляющий собой список узлов AST, из которых состоит модуль. В этом примере с Python 3 (без Python 2 под рукой) это (только имена классов) [Import, Expr, Assign, While, Expr]. Не совсем то, что вы просили, но так близко, как только можете.

Хорошо, с добавлением: есть намного более простой способ, чем этот. Доказать, что ничего не читает из stdin, очень сложно, это требует тщательного статического анализа (и да, если бы вы выбрали этот путь, использование AST CPython было бы в сто раз проще, чем создание собственного парсера). Это общий случай - так что вы можете получить его почти , работающий для вашего конкретного варианта использования, с большой работой. Однако, во-первых, будет гораздо проще предотвратить это - я не очень хорошо знаю API C, но должен быть какой-то способ настроить __builtins__ и удалить input, raw_input, sys.stdin и др.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...