Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Lua 2 
:(
    Опции темы
Lazin
Дата 7.10.2007, 22:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Часть вторая.
В предыдущей статье было показано, как передать данные интерпретатору lua, как загрузить и выполнить скрипт и как узнать результат его работы. Практической пользы в этом нет абсолютно никакой, но только до тех пор, пока мы не научимся управлять выполнением программы, через lua скрипт. Чтобы это стало возможным, нужно сделать так,  чтобы скрипт мог вызвать функцию программы.
Чтобы интерпретатор мог вызвать вашу функцию, программа, сперва, должна эту функцию зарегистрировать.
lua_register(lua_State*, Имя функции, Адрес функции)
Функция должна возвращать значение типа int и получать в качестве параметра указатель на lua_State:
Код

int glue_function(lua_State* L);

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

int count = lua_gettop(L);

Затем функция может обращаться к элементам в стеке ( lua_to...(lua_State*, index) [вместо многоточия следует поставить нужный тип, например bool string и тд] ), имеющим индексы i >= 1 i <= count. Эти элементы могут иметь разные типы, функция должна проверять перед использованием типы переданных ей аргументов (функциями lua_is...(lua_State*, index) ), так как интерпретатор lua в момент вызова функции из кода lua не выполняет таких проверок (он не проверяет даже количество переданных в функцию аргументов, не то что их тип ). Чтобы возвратить значение, функция должна поместить в стэк возвращаемые значения (функции lua_push...) и возвратить их количество. Функция может вернуть множество значений (это называется кортеж), причем для функции lua абсолютно естественно, возвращать переменное число параметров.
Следующий пример иллюстрирует сказанное, программа регистрирует функцию print_arg, которая печатает количество переданных ей параметров, сами параметры и возвращает количество параметров. Скрипт использует эту функцию по назначению.
Код


#include "stdafx.h"

extern "C" {
#    include "lua.h"
#    include "lauxlib.h"
#    include "lualib.h"
}
#include <stdlib.h>
#include <stdio.h>
#include <string>


//Эта функция может принимать переменное число параметров через L
int stack_print (lua_State* L)
{
    int n = lua_gettop(L);//получаем количество параметров переданных функции
    printf("args: %d\n", lua_gettop(L) );
    for (int i = 1; i <= n; ++i)
    {
        if (lua_isnumber(L, i))//проверяем тип i-го параметра
            //если это вещественное число выводим его на экран
            printf("result[%d] = %f\n", i, lua_tonumber(L, i));
        else if (lua_isstring(L, i))//проверка на строку
            printf("result[%d] = %s\n", i, lua_tostring(L, i));
        else if (lua_istable(L, i))//если таблица
        {    lua_pushnil(L);//кладем на вершину стека NULL
            while ( lua_next(L, i) )//эта функция берет значение из стека (по индексу -1),
            //и использует его в качестве ключа для поиска по таблице, которая
            //находится в стеке по индексу i, в случае если находит, добавляет в
            //стек пару ключ - значение, следующие в таблице после ключа находившегося в стеке
            //если больше нет значений, ф-я возвращает 0
            //lua_next используется для перебора элементов таблицы
            {
                /*
                    Состояние стека:
                    [-1] value  <--Вершина стека
                    [-2] key
                    ....
                    [i] table <-- текущий элемент
                 */
                //print key value
                if (lua_type(L, -2) == LUA_TNUMBER)
                {
                    printf ( "key = %f", lua_tonumber(L, -2) );
                } else if ( lua_type(L, -2) )
                {
                    printf ("key = %s", lua_tostring(L, -2));
                }
                //print value
                if (lua_type(L, -1) == LUA_TNUMBER)
                {
                    printf ( "\tvalue = %f\n", lua_tonumber(L, -1));
                } else if ( lua_type(L, -1) )
                {
                    printf ("\tvalue = %s\n", lua_tostring(L, -1));
                }
                //удаляем значение value из стэка, что-бы на следующей итерации
                //ключ использовался для нахождения следующей пары значений из таблицы
                lua_pop(L, 1);
                /*
                    Состояние стека:
                    [-1] key  <--Вершина стека
                    ....
                    [i] table <-- текущий элемент
                 */
            }
        }
        else if (lua_isuserdata(L, i)) //пользовательский тип данных
        {
            void* udata = lua_touserdata(L, i);
            printf("lua userdata %06", udata);
        }
    }
    //возвпащаем один параметр - количество переданных значений
    lua_pushinteger(L, (ptrdiff_t)n);
    return 1;//сие означает что возвращается одно значение
}


int main(void)
{
    int status, result;
    lua_State *L;

    L = lua_open();//Новая виртуальная машина луа
    
    luaL_openlibs(L);//Открываем библиотеки base table string io math 

    lua_register(L,"print_arg", &stack_print);//Регистрируем функцию
    
    
    status = luaL_loadfile(L, "script.lua");//загружаем файл
    if (status) {
        printf("file not found or syntax error\n");
        return 1;
    }

    result = lua_pcall(L, 0, LUA_MULTRET, 0);//выполняем программу, 
    //точка входа в которую, расположена на вершине стека
    if (result) {
        printf("runtime error\n");
        return 1;
    }

    lua_close(L); //Done

    return 0;
}


код скрипта:

Код

-- script.lua
x = 8
x = print_arg(5, x, 'lua')
io.write('x = '..x..'\n')
local table        = {}
table['pi']    = 3.14159
table[3.14159]    = 'pi'
print_arg(table)


Этот пример, уже намного более практичен. С помощю склеивающих функций вы можете изменять  часть логики, не перекомпилируя проект, просто изменив скрипт. В следующей статье я покажу как реализовать в lua возможность, которая не поддерживается этим языком напрямую – объектно ориентированное программирование.
PM MAIL Skype GTalk   Вверх
Duplex
Дата 15.10.2007, 07:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 25
Регистрация: 16.7.2007
Где: Астрахань

Репутация: нет
Всего: нет



А как можно вызвать функцию Lua с аргументами из C++?
PM MAIL ICQ   Вверх
Lazin
Дата 15.10.2007, 08:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



PM MAIL Skype GTalk   Вверх
Dronchik
Дата 15.10.2007, 09:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Звукач ёмаё
**


Профиль
Группа: Участник
Сообщений: 451
Регистрация: 1.5.2007

Репутация: 0
Всего: 37



думаю статью можна перенести в раздел "Программирование игр, графики и исскуственного интелекта".


--------------------
Вместо слов делай дело, от которого ты фанатеешь. (с)

PM MAIL WWW ICQ   Вверх
Duplex
Дата 15.10.2007, 13:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 25
Регистрация: 16.7.2007
Где: Астрахань

Репутация: нет
Всего: нет



Спасибо...
PM MAIL ICQ   Вверх
Torsten
Дата 13.7.2008, 12:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 10.6.2008
Где: Pskov

Репутация: 3
Всего: 7



Lazin, 
Спасибо, хорошие статьи.
--------------------
We have no begining, we have no end. We are infinite.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1231 ]   [ Использовано запросов: 23 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.