Разбор аргументов функции без разделителей аргументов - PullRequest
3 голосов
/ 21 мая 2019

Я работаю над проектом, в котором мне нужно перевести NetLogo на другой язык программирования. Я использую Boost Spirit и уже реализовал некоторые грамматики проекта, которые хранят простой синтаксис кода в AST.

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

Например, вызов функции может выглядеть как

id1 id2 id3 id4

Это может быть:

  • id3 - это функция, которая имеет id4 в качестве аргумента (скажем, возвращаемое значение id5), а id1 - это функция, которая имеет id2 и id5 в качестве аргументов

Но это также может быть:

  • id1 имеет id2 id3 id4 в качестве аргументов (все, кроме id1 являются именами переменных)

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

  • Как можно / нужно хранить количество аргументов, которое требуется функции для использования Boost Spirit? Может быть, использовать другую таблицу символов с семантическими действиями при разборе определения функции?
  • Как только я знаю, как получить необходимое количество аргументов, как я могу получить это значение, когда найду идентификатор функции при синтаксическом анализе выражения?
  • Это хорошее решение использовать символы для различения имен переменных от имен функций?

1 Ответ

0 голосов
/ 24 мая 2019

Наконец, я сделал следующее:

  • Создал таблицу символов, используя имя функции в качестве ключа и количество аргументов в качестве сохраненных данных.
qi::symbols<char, int> f_args;
  • Использовал семантическое действие в анализаторе функций для получения списка имен и аргументов функции и отправки его во внешнюю функцию для сохранения данных в таблице символов.
void store_function (std::string name, std::list<std::string> args) {
    f_args.add(name, args.size());
    std::cout << name << " " <<  args.size() << std::endl;
}
function_ = (
        lexeme[(string("to-report") | string("to")) >> !(alnum | '_')]  // make sure we have whole words
   >   identifier 
   >   ('[' > argument_list > ']')
   >   body
   >   lexeme[string("end") >> !(alnum | '_')]
) [ phx::bind(&store_function, _2, _3) ];
  • Когда имя функции находится вне определения функции (то есть вызова функции), я загружаю данные, хранящиеся в таблице символов, чтобы использовать их в директиве повторения, и ожидаю точное числоаргументы, в которых нуждается функция.
function_call = 
    function_name >> 
    repeat( phx::ref(n_args) )[identifier];

function_name = 
    !lexeme[keywords >> !(alnum | '_')] >> 
    &lexeme[f_args [phx::ref(n_args) = _1] >> !(alnum | '_')] >> 
    raw[lexeme[(alpha | '_') >> *(alnum | '_' | '-')]];

Единственный вопрос, на который этот ответ не отвечает - последний.Надеюсь, кто-то с большим опытом в этой области объяснит это.

...