Avançar para a área de conteúdo

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Todas as informações enviadas são seguras.

  • Fechar [x]

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Todas as informações enviadas são seguras.

  • Fechar [x]

Lua Embarcada a Aplicativos que Podem Ter Script

Incorporar Scripts de Aplicativos Utilizando uma Linguagem Pequena Criada para Tarefas

Peter Seebach, Author, Freelance
Peter Seebach coleciona dispositivos pequenos que executam em Linux. Ele está cansado de ouvir piadas sobre criar um cluster Beowulf a partir deles.

Resumo:  A linguagem de programação Lua é uma linguagem de script pequena especificamente criada para ser embarcada em outros programas. A API C da Lua permite, excepcionalmente, que o código simples e limpo chame tanto Lua a partir de C quanto C a partir de Lua. Isso permite que os desenvolvedores que desejam uma linguagem de script de tempo de execução conveniente implementem facilmente os elementos básicos da API, necessários à linguagem de script, e depois usem o código Lua a partir de seus aplicativos. Este artigo apresenta a linguagem Lua como uma ferramenta possível para simplificar tarefas de desenvolvimento comuns e discute alguns dos motivos pelos quais embarcar primeiramente uma linguagem de script.

Data:  27/Jan/2009
Nível:  Intermediário
Atividade:  2026 visualizações
Comentários:  


Lua é uma linguagem de script pequena. Quão pequena? Ela usa um recurso de correspondência de padrões customizado, em vez de expressões comuns POSIX, pois uma implementação de expressão comum completa é substancialmente maior que todas as bibliotecas Lua padrão juntas; a correspondência de cadeia mais simples fornecida pela Lua, embora não tão poderosa, é uma fração de seu tamanho.

As variáveis Lua não possuem tipos tão rígidos; é possível verificar o tipo de um valor, mas não há nada que impeça um tipo de variável de alterar com o tempo. Essas duas escolhas são adequadas para uma linguagem de script. O sistema de tipos da Lua é razoavelmente simples, mas bem flexível. Matrizes e matrizes associativas são combinadas em um único tipo, chamado tabelas. Cadeias, números (somente ponto flutuante), booleanos e o tipo nil especial são tipos básicos. Talvez mais interessante, as funções também são de um tipo básico. É possível designar funções para variáveis, de forma tão fácil quanto para qualquer outro tipo; não há sintaxe especial. Existe suporte adicional para objetos userdata customizados, que podem ser definidos por desenvolvedores para manipular tipos além daqueles do sistema básico.

Uma das maiores surpresas para programadores de outras linguagens é que, na Lua, apenas false e nil são considerados falsos; qualquer objeto de um tipo não-booleano é sempre considerado verdadeiro nos testes. Embora esse comportamento possa surpreender as pessoas que estão acostumadas com linguagens C, como usar 1 e 0 para true e false, a adaptação é fácil.

A Lua é escrita em C portável. Ela também pode ser usada com C++, mas a linguagem principal é extremamente portátil; embora haja poucos recursos que exigem recursos de host, a Lua é bem executada sem dependência de plataforma. Não há nenhum conjunto grande de testes de autoconfiguração; a Lua adere ao padrão. Lua é distribuída sob a licença MIT e é totalmente livre para qualquer uso, incluindo o comercial. (Talvez este seja o motivo pelo qual muitos programadores se sentiram livres para incorporá-la em aplicativos.)

Por que uma Linguagem Embarcada?

A embarcação de uma linguagem de script oferece diversas vantagens. Eu usarei o exemplo com o qual comecei na Lua: jogo de interpretação de personagem online e em massa para múltiplos jogadores da Blizzard, World of Warcraft (WoW). A interface com o usuário para WoW é implementada inteiramente na Lua; os desenvolvedores forneceram algumas chamadas de API fundamentais para interagir realmente com o mecanismo de renderização e solicitar dados sobre o mundo, depois usaram Lua para o núcleo do código da interface com o usuário.

É muito mais fácil para o código da interface ter uma sandbox retirada de forma correta, melhorando a segurança e confiabilidade. E isso, por sua vez, significa que a Blizzard é capaz de abrir a interface com o usuário para os usuários, permitindo que eles criem código customizado para alterar a forma com a qual interagem com a linguagem.

No geral, é mais fácil trabalhar com as linguagens de script em muitos tipos de tarefas do que as linguagens de nível inferior. Uma linguagem com garbage collectore alocação implícita e matrizes associativas geralmente oferece um código mais simples que é desenvolvido mais rapidamente. Ele pode não executar rapidamente, mas, em muitos casos, isso não é um problema; as interfaces com o usuário, por exemplo, só precisam ser executadas mais rapidamente que a ação de digitar ou clicar no mouse de um usuário.

Há várias formas de usar uma linguagem de script. A primeira, e mais simples, é usá-la para controlar o comportamento de um programa, tratando o código C como um detalhe de implementação de um programa que é realmente escrito em Lua. A segunda é escrever um programa primeiramente em C e depois usar a Lua embarcada como forma de armazenar e reportar dados e configuração. A terceira, e a mais flexível, é combinar e corresponder essas abordagens, usando Lua para efetuar o script de algumas ações e o código em C para gerenciar outras. A interface simples entre Lua e C encoraja abordagens como esta.


Criando um Mecanismo

Criar um mecanismo para um programa que primariamente será escrito na Lua faz sentido quando o uso principal do tempo de CPU for integrado em operações individuais e o controle de nível superior for relativamente leve. Isso auxilia na separação de detalhes da implementação do design de nível superior. Implementar a lógica principal de um programa na Lua, e não em C, pode reduzir drasticamente o tempo de desenvolvimento.

Para esse tipo de design, você esperaria o melhor da sua interface Lua para C, para consistir da definição de funções C que serão chamadas da Lua, com a expectativa de que depois que você iniciar a execução do script, todo o uso futuro do seu código C será chamado do script.


Arquivos de Configuração que Podem Ter Script

Cada programador que eu conheço escreveu pelo menos uma parte de código que não funcionou, mas tentou armazenar valores de configuração em um arquivo e restaurou esses valores posteriormente. (Daqueles que eu usei, as listas de propriedades da Apple são provavelmente minhas favoritas.) No entanto, uma linguagem de script embarcada pode ser utilizada como o formato para esses arquivos, fornecendo aos usuários uma matriz espetacular de opções de configuração. O gerenciador de janelas Ion utiliza Lua para seus arquivos de configuração, permitindo que os usuários criem configurações poderosas e flexíveis.

O que torna esse recurso excelente aos usuários é que eles não estão mais restritos a designações simples de valores; os arquivos de configuração expressos como Lua podem ter comentários, condicionais e muito mais. É possível fornecer uma API limitada para a aquisição de dados que podem influenciar escolhas de configuração.


Combinando e Correspondendo

É bem possível haver um bate bola entre Lua e C, já que o intérprete de Lua é reentrante. Tudo bem se seu programa C chamar o intérprete de Lua em um script, que chamará uma função C, que então usará o intérprete de Lua novamente.

World of Warcraft utiliza, essencialmente, esse modelo para sua interface com o usuário; as chamadas de Lua na interface com o usuário podem fazer chamadas novamente no mecanismo e o mecanismo distribui eventos para o código da interface com o usuário escrito em Lua. O resultado é uma interface flexível com boa separação e segurança, que fornece aos usuários a possibilidade de efetuar operações com pouco risco que acionarão estouros de buffer no aplicativo ou causarão travamento. Em uma API baseada em C, o código integrado certamente causaria um travamento; usando a interface Lua, se o código da interface com o usuário puder causar um travamento, haverá um erro que precisará ser corrigido.


Criando e Utilizando Lua

Compilar em Luaé fácil, basta executar make <platforma>; é possível se basear somente em posix ou até mesmo a ansi se não quiser contar com recursos específicos da plataforma. O build produz uma biblioteca, liblua.a, que é possível vincular a programas. Parabéns! Você embarcou Lua. É claro que usá-la exige um pouco mais de trabalho.

A re-entrância de Lua vem da manutenção de todo o estado do intérprete em um objeto; pode haver vários estados, que não compartilham variáveis e nenhum item global compartilhado entre eles. Para interagir com Lua, você deve começar criando um estado para Lua:

lua_State *l;
l = lua_open();

Se a chamada lua_open() falhar, ela retornará um ponteiro nulo. Caso contrário, você terá um estado válido para o intérprete de Lua. É claro que não ter bibliotecas não é muito bom. É possível adicionar bibliotecas padrão a ele com a função luaL_openlibs():

luaL_openlibs(l);

A estado da Lua agora está pronto para executar códigos. A seguir um loop de amostra para um programa que simplesmente executa seus argumentos como código Lua:


Lista 1. Executando Argumentos como Código Lua


  for (i = 1; i < argc; ++i) {
    if (luaL_loadbuffer(l, argv[i], strlen(argv[i]), "argument")) {
      fprintf(stderr, "lua couldn't parse '%s': %s.\n",
		 		 argv[i], lua_tostring(l, -1));
      lua_pop(l, 1);
    } else {
      if (lua_pcall(l, 0, 1, 0)) {
        fprintf(stderr, "lua couldn't execute '%s': %s.\n",
		 		 argv[i], lua_tostring(l, -1));
        lua_pop(l, 1);
      } else {
        lua_pop(l, lua_gettop(l));
      }
    }
  }

A função luaL_loadbuffer() compila um script no código Lua; se houver um erro de sintaxe, será onde a falha será observada. A mensagem de erro é retornada na pilha. Caso contrário, o código compilado poderá ser executado usando a função lua_pcall(). Novamente, se houver um erro, ele será retornado na pilha. Observe que cada chamada da linguagem C ou sobre a Lua obtém um estado da Lua como argumento; não há estado padrão.

Entendendo a Pilha da Lua

O intérprete de Lua utiliza uma interface de pilha para comunicação com o código de chamada. Os dados que estão sendo enviados para o código Lua são colocados na pilha pelo código C; as respostas do intérprete de Lua também são colocadas na pilha. Se o código transmitido para luaL_loadbuffer() for inválido, a mensagem de erro será colocada na pilha.

Itens na pilha têm tipos e valores. A função lua_type() consulta o tipo de um objeto; as funções lua_to<tipo>() (como lua_tostring()) produz valores forçado para tipos C específicos. O código escrito na Lua sempre obedece estritamente o modelo de pilha; o código C, no entanto, pode explorar o resto da pilha ou até mesmo inserir valores nela.

Essa interface é simples, mas muito poderosa. O código a ser executado não é tratado de forma diferente; ele simplesmente é colocado na pilha para ser executado pela função lua_pcall().

Utilizando lua_pcall()

A função lua_pcall() obtém três argumentos diferentes do estado de Lua no qual irá operar. O código a ser executado não é um desses argumentos; ele será colocado na pilha por luaL_loadbuffer() ou por outra função que o obtém. Em vez disso, lua_pcall() obtém como argumento o número de argumentos da pilha para transmitir ao código que está prestes a ser executado, o número de resultados a esperar e, opcionalmente, um manipulador de erros. Para chamar uma função, você primeiro obtém a função e depois os argumentos que ela terá (na ordem). Os argumentos retornados são colocados na mesma ordem; o primeiro valor retornado está na parte inferior e o último valor retornado está na parte superior.

Tanto para enviar argumentos quanto para obter valores de retorno, Lua corrige silenciosamente o número de valores para corresponder aos números transmitidos para lua_pcall(); se não forem fornecidos valores suficientes, o lembrete será preenchido com valores nil, e se existirem extras, eles serão descartados silenciosamente. (Este comportamento é igual ao de Lua em várias operações de designação.)

O manipulador de erros, se algum for fornecido, é o índice na pilha do código Lua para manipular todos os erros que ocorrerem. Neste artigo de visão geral, omitirei discussões detalhadas sobre a manipulação de erros; o que é importante saber é que, primeiro, há uma manipulação de erros e, segundo, ela é feita na Lua. Isso será útil.


Embarcando C em Lua

Criar funções em C que serão utilizadas por Lua é surpreendentemente fácil. Se você já escreveu códigos para embarcar em outra linguagem de script, provavelmente ficará surpreso. Aqui está uma função C, que, fornecido um número x, retorna x + 1:


Lista 2. Função C a Ser Utilizada por Lua


int
l_ink(lua_State *L) {
        int x;
        if (lua_gettop(L) >= 0) {
                x = (int) lua_tonumber(L, -1);
                lua_pushnumber(L, x + 1);
        }
        return 1;
}

A função é chamada com um argumento de estado de Lua; novamente, toda interação entre C e Lua ocorre através da pilha de estado da Lua. O valor de retorno é o número de objetos que a função colocou na pilha. Para disponibilizar essa função para Lua, você deve fazer duas coisas; primeiro criar um objeto Lua que represente essa função e depois nomeá-lo:

lua_pushcfunction(L, l_ink);
lua_setglobal(L, "ink");

Você utiliza lua_pushcfunction() para converter um ponteiro de função C em um objeto Lua interno. Este objeto, claro, é colocado na pilha. A função lua_setglobal() então designa o valor principal na pilha para uma variável global nomeada. Como as funções são apenas valores na Lua, isso cria uma função que pode ser chamada.

A interface de pilha simplifica isso drasticamente; não há necessidade de definir ou declarar os argumentos que a função obtém. Mas isso não importa porque a Lua é muito flexível sobre como o código é chamado. É possível, no entanto, verificar algumas coisas mais cuidadosamente, se desejar. A função luaL_checknumber() também pode ser utilizada para verificar argumentos, imprimindo uma mensagem de erro informativa e abortando a execução da função.


Fazendo Bom Uso de Scripts Embarcados

A simplicidade da Lua integrada em códigos em outras linguagens (mas especialmente na C) a torna um alvo fácil para melhorar substancialmente a funcionalidade de programas em outras linguagens. Esta é uma alternativa real e viável de criar sua própria linguagem de configuração ou escrever seu próprio analisador de expressões.

Algumas coisas podem surpreender as pessoas que costumavam trabalhar com linguagens de script muito maiores. A primeira é que o custo da configuração de um intérprete da Lua é muito pequeno; se você quiser executar algo em uma sandbox, prossiga e o faça. A Lua obteve muitos recursos de segurança que eu não mencionei aqui, mas você deve estar ciente de que é possível criar sandboxs efetivas, mesmo dentro de um único estado da Lua.

As funções que simplesmente retornam dados sobre o estado do seu programa criam uma ferramenta maravilhosa para scripts e dados de configuração. Se você quiser começar a criar algumas lógicas de nível superior na Lua, poderá fazê-lo de forma muito simples e eficiente. Embora muitas linguagens de script contraditoriamente aceitem a necessidade de trabalhar em conjunto com códigos de outras linguagens, a Lua provavelmente é o exemplo mais claro de uma linguagem totalmente criada para funcionar em conjunto com outras linguagens.


Recursos

Aprender

Obter produtos e tecnologias

Discutir

Sobre o autor

Peter Seebach

Peter Seebach coleciona dispositivos pequenos que executam em Linux. Ele está cansado de ouvir piadas sobre criar um cluster Beowulf a partir deles.

Ajuda para Relatar Abuso

Relatar abuso

Obrigado. Esta entrada foi sinalizada para atenção do moderador.


Ajuda para Relatar Abuso

Relatar abuso

Falha no envio do Relatório de abuso. Tente novamente mais tarde.


developerWorks: Registre-se


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Selecione seu nome de exibição

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

(Deve possuir de 3 a 31 caracteres.)


Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Classificar este artigo

Comentários

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Linux, Software livre
ArticleID=382593
ArticleTitle=Lua Embarcada a Aplicativos que Podem Ter Script
publish-date=01272009
author1-email=crankyuser@seebs.plethora.net
author1-email-cc=

Conheça a IBM da sua cidade

Virtual Branch Office Brasil

A IBM está mais perto do que você imagina!


Tags

Help
Use o campo de pesquisa para encontrar todos os tipos de conteúdo no My developerWorks com essa tag.

Use a barra de rolagem para ver mais ou menos tags.

Tags populares mostra as principais tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Minhas tags mostra suas tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Use o campo de pesquisa para localizar todos os tipos de conteúdo no Meu developerWorks com essa tag. Tags populares mostra as tags principais para essa zona de conteúdo particular (por exemplo, tecnologia Java, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere). Minhas tags mostra as suas tags para essa zona de conteúdo em particular (por exemplo, tecnologia Java, Linux, WebSphere).