Управление библиотеками и импортом на языке программирования - PullRequest
0 голосов
/ 03 апреля 2010

Я создал интерпретатор для глупого языка программирования в C ++, и вся структура ядра завершена (Tokenizer, Parser, Interpreter, включая таблицы символов, функции ядра и т. Д.).

Теперь у меня проблема с созданием и управлением библиотеками функций для этого интерпретатора (позже я объясню, что я имею в виду)

Так что в настоящее время мой основной обработчик функций ужасен :

// Simplified version
myLangResult SystemFunction( name, argc, argv )
{
      if ( name == "print" )
      {
         if( argc < 1 )
         {
           Error('blah');
         }
         cout << argv[ 0 ];
       } else if ( name == "input" ) {
         if( argc < 1 )
         {
           Error('blah');
         }
         string res;
         getline( cin, res );
         SetVariable( argv[ 0 ], res );
       } else if ( name == "exit ) {
         exit( 0 ); 
}

А теперь подумайте друг о друге, если он в 10 раз сложнее, а в системе еще 25 функций. Неустойчив, чувствует себя ужасно, ужасно.

Итак, я подумал: как создать какую-то библиотеку, которая содержит все функции и, если они импортированы, инициализировать себя и добавить свои функции в таблицу символов работающего интерпретатора.

Однако в этот момент я действительно не знаю, как продолжать.

То, чего я хотел добиться, - это, например, наличие библиотеки строк (extern?) Для моего языка, например, строки, и она импортируется из программы на этом языке, например:

import string
myString = "abcde"
print string.at( myString, 2 ) # output: c

Мои проблемы:

  • Как отделить библиотеки функций от основного интерпретатора и загрузить их?
  • Как получить все их функции в списке и при необходимости добавить их в таблицу символов?

Что я думал сделать:

В начале интерпретатора, поскольку все библиотеки скомпилированы с ним, каждая отдельная функция вызывает что-то вроде RegisterFunction( string namespace, myLangResult (*functionPtr) );, которое добавляет себя в список. Когда import X вызывается из языка, список, созданный с помощью RegisterFunction, добавляется в таблицу символов.

Недостатки, которые приходят на ум:

Все библиотеки находятся непосредственно в ядре интерпретатора, размер увеличивается, и это определенно замедлит его.

Ответы [ 3 ]

1 голос
/ 03 апреля 2010

Если ваш интерпретатор реализован в виде библиотеки, он будет вызываться из кода C ++ других людей. Для них весьма разумно вызывать функции из вашей библиотеки из собственного кода, чтобы добавить функцию к интерпретатору. Это то, что делает мой собственный оценщик выражений. как то в коде пользователя:

Interpreter in;    // an instance of the interpreter
in.AddFunc( lenfun, "length", 1 );
in.AddFunc( catfun, "concat", 2 );

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

1 голос
/ 03 апреля 2010

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

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

0 голосов
/ 03 апреля 2010

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

Более простой подход - сохранить глобальную таблицу символов со связанными обработчиками.

Используйте std :: map (или hash_map) для гораздо более быстрого поиска функции, чем ваша конструкция if / else. Пусть все функции зарегистрируются в таблице символов.

«Обработчики», хранящиеся в таблице символов, могут быть простыми объектами (или указателями на функции) и могут выполнять собственную проверку аргументов.

class FuncHandler {
  virtual MyLangResult Run(argv, argc) = 0;
}

typedef std::map<string, FuncHandler*> FuncTableType;

// Simplified version
myLangResult SystemFunction(name, argc, argv )
{
  FuncTableType::const_iterator it = function_table_.find(name);
  if (it == function_table_.end()) return Error("Unknown function: " + name);
  return it->second(argc, argv);
}

Я написал некоторый код для самостоятельной регистрации классов в этом вопросе, но здесь это не обязательно: Доступ к функциям C ++ из хранилища текста

...