Você está na página 1de 181

José Augusto N. G.

Manzano

Novatec
Copyright © 2018 da Novatec Editora Ltda.
Todos os direitos reservados e protegidos pela Lei 9.610 de 19/02/1998. É proibida a reprodução
desta obra, mesmo parcial, por qualquer processo, sem prévia autorização, por escrito, do autor e
da Editora.
Editor: Rubens Prates
Revisão gramatical: Tássia Carvalho
Editoração eletrônica: Carolina Kuwabata
Capa: Carolina Kuwabata
ISBN: 978-85-7522-671-1
Histórico de edições impressas:
Abril/2018 Primeira edição
Novatec Editora Ltda.
Rua Luís Antônio dos Santos 110
02460-000 – São Paulo, SP – Brasil
Tel.: +55 11 2959-6529
Email: novatec@novatec.com.br
Site: www.novatec.com.br
Twitter: twitter.com/novateceditora
Facebook: facebook.com/novatec
LinkedIn: linkedin.com/in/novatec
Sumário

Agradecimentos
Prefácio
Sobre o autor
Capítulo 1 ■ Introdução
1.1 Linguagem de programação Lua
1.2 Obtenção do interpretador Lua
1.3 Interatividade

Capítulo 2 ■ Programação sequencial


2.1 Elementos operacionais básicos
2.2 Atribuições e coerções
2.3 Entrada, processamento e saída
2.4 Entrada alternativa de dados
2.5 De nição de pausa
2.6 Compilação de programas
2.7 Exercícios de xação

Capítulo 3 ■ Programação com decisão


3.1 Condição, decisão e operadores relacionais
3.2 Desvios condicionais
3.2.1 Desvio condicional simples
3.2.2 Desvio condicional composto
3.3 Operadores lógicos
3.4 Outros desvios
3.4.1 Desvio condicional encadeado
3.4.2 Desvio condicional sequencial
3.4.3 Desvio condicional sobreposto
3.5 Desvio seletivo simulado com ação incondicional
3.6 Divisibilidade
3.7 Exercícios de xação
Capítulo 4 ■ Programação com laços
4.1 Laço pré-teste
4.1.1 Fluxo condicional verdadeiro
4.1.2 Fluxo condicional falso
4.2 Laço pós-teste
4.2.1 Fluxo condicional falso
4.2.2 Fluxo condicional verdadeiro
4.3 Laço iterativo
4.4 Laço seletivo
4.5 Interrupção na execução de laços
4.6 Consistência de entrada de dados
4.7 Exercícios de xação

Capítulo 5 ■ Programação com funções


5.1 Funções internas
5.2 Escopo e visibilidade de variáveis
5.3 Funções externas
5.3.1 Passagem de parâmetro
5.3.2 Parâmetros arbitrários
5.4 Funcionalidades especiais
5.4.1 Função temporal
5.4.2 Função aleatoriedade
5.4.3 Função recursividade
5.4.4 Função anônima (Lambda)
5.4.5 Função enclausurada (Clousure)
5.5 Biblioteca do programador (Módulo)
5.6 Tratamento de exceções
5.7 Exercícios de xação

Capítulo 6 ■ Estruturas de dados


6.1 Conjunto de dados
6.1.1 Estrutura de vetores
6.1.2 Estrutura de tabelas
6.1.3 Estrutura de enumeração
6.1.4 Estrutura de registros
6.2 Funções para estruturas
6.3 Estrutura metatabelas
6.4 Estrutura interna
6.5 Exercícios de xação

Capítulo 7 ■ Recursos complementares


7.1 Descrição de dados
7.2 Princípio de orientação a objeto
7.3 Princípio de concorrência
7.4 Passagem de parâmetro por matriz
7.5 Conversão de tipos de dados
7.6 Arredondamentos e ajustes
7.7 Conversão de bases numéricas

Capítulo 8 ■ Arquivos em disco


8.1 De nição de arquivos
8.2 Tipos de arquivos
8.2.1 Texto
8.2.2 Binário
8.3 Controle de operações
8.4 Arquivo de acesso direto
8.5 Considerações sobre arquivos binários e texto
8.6 Exercícios de xação

Referências bibliográ cas


Agradecimentos

Ao Pai Celestial, que designou em sua in nita sabedoria a direção


pro ssional de minha vida, fazendo-me descobrir ser professor. Espero
estar sendo digno dessa missão e do propósito a mim conferido.
À minha esposa Sandra e à minha lha Audrey, motivos de constante
inspiração ao meu trabalho. Pela paciência nos momentos de ausência
quando estou absorto em escrever, dedicando-me ao ensino.
A todos os alunos que passaram e passam pela minha vida, que
acreditaram e acreditam na minha pessoa e que seguiram e seguem as
orientações que lhes passo; por me incentivarem continuamente quando
me questionam sobre temas que ainda não conheço, por me levarem a um
patamar maior por exigirem, assim, que eu pesquise mais.
A você, amigo leitor, que já me conhece de outros trabalhos ou não, por
estar investindo de forma legal na obtenção deste trabalho. Obrigado por
não fazer fotocópias ou prática de pirataria com esta contribuição de
minha pessoa a você.
Vida longa e próspera.
Prefácio

Lua é uma linguagem de programação para computadores desenvolvida


no Brasil que ganhou espaço mundial. Há muitos pro ssionais
trabalhando com a linguagem em diversos países como: Rússia,
Dinamarca, Alemanha, Japão, Itália, Estados Unidos, Brasil, entre outros.
Uma das primeiras empresas a empregar Lua internacionalmente no
desenvolvimento de programas foi a Lucas Arts, de George Lucas. A Lucas
Arts adotou códigos em linguagem Lua no desenvolvimento de jogos para
uso em computadores. Hoje é muito comum encontrar jogos de outros
desenvolvedores, tal como Microsoft e Relic Entertainment, empregando
a linguagem.
Lua não é só usada no desenvolvimento de jogos, mas também em
aplicações de apoio à prospecção de petróleo (Petrobras), sistema de
monitoração de UTIs (Instituto do Coração de São Paulo – Incor),
desenvolvimento de processadores pela Intel e pela NASA no controle dos
níveis de concentração de gases para o lançamento do ônibus espacial
(http://www.lua.org/press.html); en m, Lua pode ser usada para o
desenvolvimento de qualquer tipo de programa ou sistema, seja
comercial, industrial, entretenimento ou cientí co.
Este livro pode ser utilizado em sala de aula (laboratório com prática de
programação) de cursos superiores na área de tecnologia, cursos técnicos
(ensino médio) e em atividades de treinamento empresarial.
Apresenta as bases e os primeiros passos na operação da linguagem a
partir de uma centena de exemplos aplicados como exercícios de
aprendizagem. Para xar os conceitos abordados, o livro possui uma
coleção com cerca de noventa exercícios de xação ao nal de alguns
capítulos, os quais devem ser realizados, pois levam o leitor a um patamar
superior do conhecimento, além do limite tratado na obra.
Este trabalho encontra-se dividido em oito capítulos que abordam
diversas temáticas de programação, como: variáveis, constantes,
atribuições, coerções, operadores aritméticos, expressões aritméticas,
decisões, laços, operadores aritméticos, operadores lógicos, funções,
vetores, tabelas, listas, registros, descrição de dados, módulos,
concorrência, orientação a objetos e arquivos. Este livro não aborda temas
avançados, como a integração de Lua com outras linguagens como C e
C++.
Espero que este trabalho seja útil ao leitor iniciante e, assim, consiga
ajudá-lo a compreender o uso dessa interessante linguagem de
programação. A todos, um grande abraço.
Sobre o autor

José Augusto Navarro Garcia Manzano é professor e mestre formado em Análise e


Desenvolvimento de Sistemas, Ciências Econômicas e Licenciatura em
Matemática. Atua na área de Tecnologia da Informação, Computação e
Informática (desenvolvimento de software, ensino e treinamento) desde
1986. Participou do desenvolvimento de aplicações computacionais para
áreas de telecomunicações e comércio. Na carreira docente, iniciou sua
atividade em cursos livres, trabalhando posteriormente em empresas de
treinamento e atuando, desde então, nos ensinos técnico e superior.
Atualmente é professor com exclusivo no IFSP (Instituto Federal de
Educação, Ciência e Tecnologia de São Paulo, antiga Escola Técnica
Federal). Em sua carreira, desenvolveu competências e habilidades para
ministrar componentes curriculares de Lógica de Programação
(Algoritmos), Estrutura de Dados, Microinformática, Informática,
Linguagens de Programação Estruturada, Linguagens de Programação
Orientada a Objetos, Engenharia de Software, Sistemas de Informação,
Engenharia da Informação, Arquitetura de Computadores e Tecnologias
Web. Possui conhecimento de uso de diversas linguagens de programação,
tais como: Classic BASIC, COMAL, Logo, Assembly, Pascal, FORTRAN,
C, C++, D, Java, Modula-2, Structured BASIC, C#, Lua, HTML,
XHTML, Javascript, VBA e Ada. Possui mais de uma centena de obras
publicadas, além de artigos publicados no Brasil e no exterior.
CAPÍTULO 1

Introdução

Este capítulo apresenta informações sobre a linguagem brasileira de


programação de computadores Lua, sua aquisição, instalação e uso inicial
nos sistemas operacionais Mac OS X, Linux e Microsoft Windows.

1.1 Linguagem de programação Lua


A linguagem brasileira de programação de computadores Lua foi
apresentada em 1993 pelas mãos dos pesquisadores: Waldemar Celes,
Roberto Ierusalimschy e Luiz Henrique de Figueiredo, colaboradores do
Tecgraf/PUC-Rio: Grupo de Tecnologia em Computação Grá ca, a partir
de uma necessidade interna do Departamento de Informática em
desenvolver e atender a parceria com a Petrobras.
Após o trabalho com a Petrobras surgiram outros projetos envolvendo o
uso e a aplicação da nova linguagem no desenvolvimento de um sistema
de intranet para o Departamento de Informática da PUC-Rio, em 1994.
Lua passou a ser utilizada em outros projetos, como o desenvolvimento de
jogos pela empresa LucasArts, destacando-se Grim Fandango, Escape
from Monkey Island, World of Warcraft, GTA IV, Crysis e Street Fighter 4.
A LucasArts, do cineasta George Lucas, foi a primeira empresa a usar Lua
para o desenvolvimento de jogos. Em seguida, vieram outras empresas,
destacando-se Microsoft no desenvolvimento de jogos para o Xbox
(UNIVERSIA, 2002), Adobe no desenvolvimento do programa Photoshop
Lightroom e Wireshark da Wireshark Foudation (Info Exame, 2009). A
linguagem Lua é usada em diversos países, como: Rússia, Dinamarca,
Alemanha, Japão, Itália, Estados Unidos, Brasil, entre outros.
Lua é descendente das linguagens SOL (Simple Object Language) e DEL
(Data-Entry Language), anteriormente usadas em projetos de engenharia
para a Petrobras. Então passou a estender aplicações de linguagens mais
pesadas, como C e C++, sendo utilizada no desenvolvimento de sistemas
de intranet, construção de sites para web e jogos eletrônicos.
Lua é uma linguagem rápida, robusta, leve, de fácil aprendizagem,
distribuída em regime de software livre. Combina uma estrutura sintática
simples para o desenvolvimento de sub-rotinas com poderosas
construções para descrição de dados. Opera dados de modo dinâmico
não necessitando declarar os tipos de dados a serem utilizados.
Talvez os usuários avançados se interessem no estudo do código-fonte da
linguagem, disponível para a versão 5.3.4 (lançado em janeiro de 2017) em:
https://www.lua.org/ftp/lua-5.3.4.tar.gz.

1.2 Obtenção do interpretador Lua


Para utilizar a linguagem Lua, é necessário possuir instalado em seu
computador o interpretador da linguagem que pode ser adquirido no site
http://luabinaries.luaforge.net/ (Figura 1.1).
Em seguida, escolha no menu lateral esquerdo a opção Download e, na lista
apresentada, selecione a última versão disponível - no momento de
elaboração deste texto, era 5.3.4.
As opções para obtenção da linguagem Lua abrangem os sistemas
operacionais Windows de 32 e 64 bits, Mac OS X e Linux de 64 bits.
Copie para seu computador os arquivos binários executáveis e
suplementares de biblioteca do sistema operacional desejado, podendo
ser:
Tabela 1.1 – Opções de download
Microsoft Windows

lua-5.3.4_Win32_bin.zip Executável Windows x86

lua-5.3.4_Win32_dllw4_lib.zip Biblioteca Windows x86 (Compatibilidade MingW 4)

lua-5.3.4_Win64_bin.zip Executável Windows x64


lua-5.3.4_Win64_dllw4_lib.zip Biblioteca Windows x64 (Compatibilidade MingW 4)

Mac OS X Intel

lua-5.3.4_MacOS1011_bin.tar.gz Executável MacOS X Intel

lua-5.3.4_MacOS1011_lib.tar.gz Biblioteca MacOS X Intel

Linux

lua- Executável Linux x64


5.3.4_Linux319_64_bin.tar.gz

lua-5.3.4_Linux319_64_lib.tar.gz Biblioteca Linux x64

Os procedimentos de instalação descritos são o mais simples possível,


garantindo o conjunto mínimo necessário para uso da linguagem a partir
da linha de comando (CUI – Character User Interface ou CLI –
Command Line Interface) de cada um dos sistemas operacionais citados.
No caso do sistema operacional Microsoft Windows 32 bits (ou 64 bits),
crie uma pasta a partir da raiz do disco rígido com nome lua5 e dentro
dela descompacte os conteúdos dos arquivos baixados.
No caso do sistema operacional Mac OS X ou Linux, crie a partir da
pasta do usuário a pasta lua5, e descompacte nela os conteúdos dos
arquivos baixados.
Figura 1.1 – Site LuaBinaries.
Para usar o interpretador, vá à pasta lua5 por meio da janela Prompt do MS-
DOS no Windows ou por meio da janela Terminal no Linux ou Mac OS X e
informe no prompt a instrução:
lua53 nome_do_programa.lua
Os programas escritos em Lua, quando gravados, devem ser acrescidos da
extensão .lua para que o interpretador consiga identi car o programa a
ser executado.

1.3 Interatividade
A linguagem de programação Lua possui um ambiente de trabalho que
pode ser usado interativamente. Nesse modo, é possível realizar algumas
tarefas operacionais. Na linha de comando prompt (modo terminal) do
sistema operacional em uso, faça a chamada do programa lua53, acione
<Enter>. Será apresentada a mensagem de identi cação:
Lua 5.3.4 Copyright (C) 1994-2017 Lua.org, PUC-Rio
>
O símbolo “>” caracteriza o prompt do ambiente interativo da linguagem
Lua. Para sair do prompt do ambiente Lua e retornar ao terminal do
sistema operacional, basta executar o comando os.exit() e, em seguida,
acionar a tecla <Enter> ou <Return> ou ainda usar as teclas de atalho <Ctrl>
+ <c> ou as teclas de atalho <Ctrl> + <z> + <Enter>, dependendo do sistema
operacional em uso.
Dentro do ambiente interativo, é possível informar comandos com o
sentido de obter respostas imediatas. Por exemplo, desejando-se obter o
resultado da soma do valor 7.5 com o valor 4.8, basta executar a linha de
comando:
print(7.5 + 4.8)
Após acionar a tecla <Enter> ou a tecla <Return>, o resultado obtido será
12.3.
Veja a seguir uma série de operações com cálculos matemáticos que
podem ser efetivadas junto ao ambiente interativo.
print(-2 + -3)
print(2 * 3)
print(10 / 4)
print(10 % 4)
print(2 ^ 3)
print(2 + 5 * 3)
print(2 + (5 * 3))
print((2 + 5) * 3)
Os exemplos apresentados anteriormente resultam respectivamente nos
valores: -5, 6, 2.5, 2, 8, 17 e 21.
O ambiente interativo retorna mensagens de erro quando algo não é
escrito dentro das regras sintáticas do ambiente. Por exemplo, execute o
código:
print(2 + + 3)
Ocorrerá a apresentação da mensagem de erro: stdin:1: unexpected symbol
near '+'.
Para obter resultados de cálculos matemáticos, pode-se substituir o
comando print() pelo símbolo “=”, igual a, ou mesmo o omitir a partir da
versão 5.3 da linguagem. Dessa forma, podem ser de nidos os seguintes
cálculos.
=2*3 =2/3 =2+3 =2-3
 
2*3 2/3 2+3 2-3
Serão apresentados os resultados 6, 0.66666666666667, 5 e -1 para a
execução de ambas as linhas.
Os cálculos efetivados poderão trabalhar com outros formatos numéricos,
como valores expressos em notação cientí ca. Por exemplo, caso deseje
obter o resultado decimal do valor 9.5e2, sendo:
9.5e2
O resultado apresentará o valor 950, pois se calcula o valor 9.5
multiplicando-se por 10 e elevando-se a potência 2, ou seja, 9.5 x 102.
Experimente =9.5e-2 para obtenção do resultado 0.095.
Outra possibilidade é o uso de valores hexadecimais convertidos em
valores decimais. Por exemplo, observe os seguintes comandos.
0xa 0xA 0Xa 0XA
Ao serem executados, todos resultarão na apresentação do valor 10, pois o
valor A hexadecimal é igual ao valor 10 em decimal. Não importa como é
de nido o valor, seja em formato de caractere maiúsculo ou formato de
caractere minúsculo, o resultado será sempre apresentado.
O ambiente interativo da linguagem Lua aceita o uso de variáveis. Por
exemplo, informe as linhas de código seguintes acionando a tecla <Enter>
ou <Return> para cada linha informada.
A = 2
B = 3
print(A + B)
Observe o surgimento do valor 5 como resultado da operação. Um
cuidado que se deve tomar na de nição de variáveis é com relação ao
nome atribuído. Por exemplo, as seguintes variáveis não são as mesmas,
pois a linguagem Lua é do tipo case sensitive e diferencia caracteres
maiúsculos de minúsculos.
COR = 1
COr = 2
Cor = 3
cor = 4
cOR = 5
cOr = 6
CoR = 7
coR = 8
print(COR)
print(COr)
print(Cor)
print(cor)
print(cOR)
print(cOr)
print(CoR)
print(coR)
Outro detalhe no uso e na de nição de variáveis é a possibilidade de se
efetivar a criação de múltiplas variáveis. Por exemplo, observe o código
seguinte:
CODIGO, NOME = 1965, "Manzano"
print(CODIGO)
print(NOME)
Note que serão apresentados os valores 1965 e Manzano. O símbolo “=”
separa os conteúdos 123 e Paulo das variáveis CODIGO e NOME, fazendo a
atribuição dos valores respectivamente às variáveis indicadas.
CAPÍTULO 2

Programação sequencial

Este capítulo apresenta os princípios de programação de computadores


baseado no uso da estratégia de desenvolvimento sequencial. Será visto
como a linguagem Lua trata tipos de dados, variáveis, constantes,
operadores aritméticos, expressões aritméticas, controle de entrada e saída
de dados e formatação de valores numéricos.

2.1 Elementos operacionais básicos


Para se usar um determinado dado, é necessário que este esteja associado
a uma variável, sendo variável a região de memória principal de um
computador, previamente identi cada por um rótulo cuja nalidade é
armazenar determinado valor (dado) por certo espaço de tempo. Uma
variável possui a capacidade de armazenar apenas um valor por vez.
Considera-se valor um conteúdo numérico, alfabético, alfanumérico ou
lógico.
O nome de uma variável (também denominado rótulo) é utilizado para
sua identi cação e posterior uso dentro de um programa, portanto é
necessário estabelecer algumas regras para a de nição do nome de uma
variável:
• Nomes de variável podem ter um ou mais caracteres.
• O primeiro caractere do nome de uma variável não pode ser um
número; sempre deve ser um caractere alfabético ou um caractere “_”
(underline).
• O nome de uma variável não pode ter espaços em branco.
• Não pode ser nome de uma variável uma palavra reservada da
linguagem como o nome de uma instrução ou identi cador.
• Não podem ser utilizados outros caracteres no nome de uma variável,
a não ser que sejam letras e números, com exceção do caractere
underline “_”, que pode ser usado para simular a separação de
palavras compostas, como: NOME_ALUNO.
Uma variável pode exercer dois papéis em um programa de computador.
O papel de ação, quando é modi cada ao longo do programa para
apresentar certo resultado, ou o papel de controle, em que a variável será
“vigiada” e controlada durante a execução de um programa quando do
uso de tomada de decisões e laços para repetições de instruções.
Lua permite o uso de variáveis sob dois escopos, o local e o global. Esse
tema será explorado mais adiante, pois neste momento interessa apenas o
uso de variáveis sob a óptica do escopo global, que é a forma padrão de
trabalho no uso de variáveis.
Todo computador tem por princípio básico de funcionamento a
capacidade de processar os dados advindos do mundo externo e
transformá-los em informações úteis para seus usuários. A linguagem Lua
fornece um conjunto de tipos de dados dinâmicos, ou seja, dados que não
necessitam ser identi cados antes de seu uso, como ocorre com outras
linguagens de programação como C, C++ e Pascal, entre outras, pois Lua
identi ca de modo automático os tipos de dados a serem manipulados no
momento de seu uso, ou seja, Lua é uma linguagem que gerencia
automaticamente a memória do computador (GUTSCHMIDT, 2003).
Dessa forma, Lua opera com os seguintes tipos de dados dinâmicos:
• nil – Usado na de nição de valores inde nidos.
• boolean – Usado na de nição de valores do tipo falso (false) ou
verdadeiro (true).
• number – Usado na de nição de valores numéricos em notação
cientí ca, real ou inteiro.
• string – Usado na de nição de valores alfanuméricos delimitados
entre aspas inglesas (“ ”), aspas simples (‘ ’), colchetes duplos ([[ ]]) e
quando do uso de delimitadores de escapes.
• function – Usado na de nição de valores do tipo função.
• userdata – Usado na de nição de valores do tipo ponteiro quando
associada Lua com a linguagem C.
• thread – Usado na de nição de uxos de execução independentes
quando de aplicações com suporte a co-rotinas (esse tema será tratado
em tópico especí co).
• table – Usado na de nição de tabelas de valores (listas, matrizes ou
vetores).
O tipo de dado primitivo number é usado na representação de valores
numéricos, do tipo inteiro ou real. Por exemplo, o valor inteiro 5 pode ser
representado como:
A = 5
A = 5.0
A = 0.5e1
A = 50e-1
O tipo de dado primitivo string é usado para representar sequências de
caracteres delimitadas por aspas inglesas ou aspas simples que estejam
de nidas em uma linha de código ou por meio de colchetes duplos em
que a sequência de caracteres poderá estar escrita em mais de uma linha.
Dentro da delimitação de uma sequência de caracteres, podem-se utilizar
as sequências de escape (EMMERICH, 2009, p. 20):
\n new line (nova linha)
\t tab (tabulação horizontal)
\r carriage return (retorno de carro – <Enter>)
\v vertical tab (tabulação vertical)
\f form feed
\xxx caractere com código decimal xxx
\a bell (campainha)
\b backspace (retorno de espaço)
\" aspa inglesa (")
\' aspa simples (')
\\ barra invertida – contra barra (\)
A aplicação dos caracteres de escape dentro de uma sequência de
caracteres, ou seja, string possibilita o uso de alguns efeitos de uso. Por
exemplo:
TEXTO1 = "Utilize a tecla '<Enter>'"
TEXTO2 = 'Utilize a tecla \'<Enter>\''
Note que a variável TEXTO1 está sendo atribuída com o valor string "Utilize
a tecla '<Enter>'". Note que o uso das aspas simples na sequência de
caracteres ocorre dentro da sequência de caracteres delimitada entre aspas
tipográ cas. No entanto, a variável TEXTO2 está sendo atribuída com o
valor 'Utilize a tecla \'<Enter>\''. Perceba que, nesse caso, para utilizar
aspas simples dentro do string, é necessário usar os caracteres de escape \’
entre a palavra <Enter> para que as aspas simples sejam apresentadas.
Uma sequência de caracteres, na forma de string, pode ser delimitada
entre colchetes duplos [[texto]]. Assim sendo, é possível de nir um string
como:
TEXTO3 = [[Utilize a tecla '<Enter>']]
Ou pode-se ainda de nir uma sequência de caracteres com colchetes
duplos dispostos isoladamente como:
TEXTO4 = [[Utilize
a tecla
'<Enter>']]
Nesse caso, a mensagem será escrita em três linhas de texto exatamente
como está de nida no trecho de código indicado.
O tipo de dado primitivo function representa valores que podem ser
atribuídos a uma determinada variável que seja passada como parâmetro.
Como exemplo básico de uso desse tipo de dado, considere o seguinte:
function nome_função(PARÂMETRO)
  ação
end
 
VARIÁVEL = nome_função(PARÂMETRO)
O tipo de dado primitivo userdata permite que ocorra o armazenamento
em uma variável Lua em um ponteiro de nido num código de programa
escrito na linguagem C. Assim, userdata corresponde ao tipo ponteiro
void* da linguagem C, podendo ser utilizado apenas para comparação de
igualdade ou atribuição entre valores do mesmo tipo tanto em C quanto
em Lua. Esse tipo de dados é útil nas situações em que há a necessidade
de se fazer uma ligação entre as linguagens Lua e C (Lua-C), mas não
pode ser utilizado em programas escritos apenas com código em
linguagem Lua.
O tipo de dado primitivo table é usado para a de nição de variáveis
compostas que permitem o uso de elementos indexados em listas,
matrizes ou vetores de uma ou mais dimensões.
Além das variáveis para a elaboração de programas, há também a
necessidade de se utilizarem constantes. Uma constante é associada à
de nição de valores preexistentes, como valores que dão peso e equilíbrio
a uma fórmula matemática ou expressões matemáticas. O valor de uma
constante é um valor que não pode ser alterado ao longo da execução de
um programa. Em várias ocasiões, esse conceito será utilizado. Por
exemplo, o valor 1.23 da expressão aritmética seguinte é uma constante:
RESULTADO = ENTRADA * 1.23.
Operadores aritméticos são responsáveis pela elaboração e execução de
cálculos matemáticos em conjunto com o uso de variáveis e constantes. O
estabelecimento de cálculos matemáticos é de nido por meio de
expressões aritméticas. A Tabela 2.1 apresenta os operadores aritméticos e
algumas funções de apoio que podem ser usados na elaboração de
cálculos matemáticos por meio de expressões aritméticas:
Tabela 2.1 – Operadores aritméticos

Operador Operação Resultado

= Atribui um valor a uma variável Atribuição

+ Manutenção de sinal Positivo

- Inversão de sinal Negativo

^ Exponenciação Number

x ^ 0.5 Raiz quadrada Number

x ^ (1/n) Raiz de índice qualquer: n√x Number


Operador Operação Resultado

// Divisão com quociente inteiro Number

% Resto de divisão Number

/ Divisão com quociente real Number

* Multiplicação Number

+ Adição Number

- Subtração Number

.. Concatenação String
Considere a fórmula AREA = . RAIO2 para o cálculo da área de uma
circunferência, em que estão presentes as variáveis AREA e RAIO, a constante
(pi = 3.14159) e os operadores aritméticos de multiplicação e também a
operação de potência, elevando o valor da variável RAIO ao quadrado.
As expressões aritméticas escritas para a execução em um computador
seguem um formato um pouco diferente do conhecido na ciência
matemática. Por exemplo, a expressão: X = { 43 . [ 55 : (30 + 2) ] } será
normalmente escrita como X = ( 43 * ( 55 / ( 30 + 2) ) ). Note que as
chaves e colchetes são abolidos, utilizando em seu lugar apenas
parênteses.
Se a fórmula a ser usada fosse para calcular a área de um triângulo, em
que é necessário efetuar a multiplicação da base pela altura e em seguida
dividir esse valor pela constante 2, como caria?
Observe a Figura 2.1 com a indicação da fórmula para o cálculo da área de
um triângulo:

Figura 2.1 – Cálculo da área de triângulos.


Que deverá ser escrita como a expressão aritmética: A = (B * H) / 2.
É oportuno levar em consideração a precedência para a realização das
operações matemáticas que ocorrem de acordo com a seguinte ordem: ^
(exponenciação); * (multiplicação) e / (divisão); + (adição) e – (subtração)
e as operações de .. (concatenação).

2.2 Atribuições e coerções


As operações de atribuições estão relacionadas ao fato de transferir
explicitamente um valor a uma variável, podendo essa atribuição ocorrer
de duas formas: simples e múltipla.
As atribuições simples são de nidas de acordo com o formato VARIÁVEL =
VALOR, em que VALOR está sendo atribuído a VARIÁVEL. Atribuições múltiplas
são de nidas de acordo com o formato VARIÁVEL1, VARIÁVEL2, VARIÁVELN =
VALOR1, VALOR2, VALORN; em que VALOR1 é atribuído a VARIÁVEL1, VALOR2 é
atribuído a VARIÁVEL2 e VALORN é atribuído a VARIÁVELN.
Caso seja de nido um número de variáveis à esquerda do sinal de
atribuição diferente do número de valores à direita do sinal de atribuição,
ocorrerá automaticamente uma de duas possibilidades, ou o
preenchimento de valores das variáveis com o valor nil quando a lista de
variáveis for maior que a lista de valores ou o descarte de valores quando a
lista de variáveis for menor que a lista de valores. O recurso de atribuições
múltiplas da linguagem de programação Lua permite fazer a troca de
valores entre variáveis em apenas uma linha de código (Tabela 2.2).
Normalmente para ser realizada essa ação faz uso de três linhas de código.
Tabela 2.2 – Exemplos de trocas de valores

PASCAL C BASIC Lua

X := A; X = A; X = A

A := B; A = B; A = B A, B = B, A

B := X; B = X; B = X
Uma característica da linguagem Lua é o efeito de coerção que ocorre
quando certa operação de atribuição é realizada. Lua é uma linguagem
que de ne automaticamente para uma variável em uso o tipo de dado a
ela associado. Não é preciso de nir previamente o tipo da variável a ser
utilizada.
O efeito de coerção (conversão automática) tenta aplicar sobre uma
operação aritmética a de nição de dados do tipo numérico, mesmo
quando está em uso um dado do tipo string, que seja, é claro, a
representação de uma sequência numérica. Por exemplo:
A = 20
B = "30"
C = A + B
Observe que no caso anterior a variável C possuiria o valor numérico
inteiro 50, sendo este a soma do valor numérico inteiro 20 da variável A
com o valor caractere alfanumérico 30 da variável B, o qual é convertido
automaticamente para o seu valor numérico inteiro equivalente 30.
No caso anterior, ocorreu a soma na variável C do conteúdo da variável B
com o conteúdo da variável A. Lua entendeu o desejo de se fazer a soma
do valor numérico inteiro 20 com o valor alfanumérico 30 e processou essa
soma realizando uma operação de coerção sobre o valor 30 de nido como
string. Quando não for possível estabelecer uma operação de coerção, Lua
reportará um erro de execução.
Outra possibilidade de uso de coerção é quando se deseja concatenar um
valor numérico a um valor string de nido. Por exemplo:
A = 20
B = "Resultado = "
C = B .. A
Observe que a variável C possuiria o valor concatenado Resultado = 20, em
que o conteúdo 20 da variável A será tratado como se fosse o string 20
concatenando-o por meio do operador aritmético .. com o conteúdo
"Resultado = " da variável B.
Em momento mais oportuno à frente o tema relacionado à conversão de
tipos de dados será retomado.

2.3 Entrada, processamento e saída


A ação de entrada é responsável por permitir a um determinado usuário
de um programa fornecer os dados que serão armazenados na memória
(nas variáveis) para posterior uso na fase de processamento.
A ação de processamento pode ocorrer sobre dois aspectos: matemático
ou lógico. Um processamento é matemático quando do uso de operações
matemáticas com a aplicação dos operadores aritméticos. Um
processamento é lógico quando se usam controles em tomadas de decisão
e execução de laços ou em qualquer operação não matemática.
A ação de saída ocorre normalmente após a conclusão de uma ação de
processamento ou de uma ação de entrada, permitindo assim apresentar
para o usuário um determinado valor como resposta de uma ação
anteriormente realizada.
Uma entrada e uma saída podem ocorrer dentro de um computador de
diversas maneiras. Por exemplo, uma entrada pode ser feita via teclado,
modem, leitores ópticos, disco, scanners, entre outros. Uma saída pode ser
feita via monitor de vídeo, impressora, disco, entre outras formas. Devido
a essa variedade, os programas escritos neste livro utilizarão as instruções
io.read (para a entrada de dados via teclado) e io.write() ou print (para a
saída de dados no monitor de vídeo).
Para a ação de saída de dados, a linguagem Lua usa duas instruções,
sendo io.write(), quando se deseja manter o cursor posicionado na
mesma linha (pode-se mudar o cursor de linha se utilizada a sequência de
escape \n) após a apresentação de determinado conteúdo, ou print(),
quando se deseja que o cursor seja posicionado na linha seguinte após a
apresentação de um determinado conteúdo.
As instruções io.read() e io.write() são escritas em dois segmentos
separados por um ponto. Note que o primeiro segmento é formado pelo
componente io (input/output) que informa que os métodos read e write
pertencem a uma biblioteca denominada io (biblioteca padrão de entrada
e saída).
Para colocar em prática o exposto, considere o desenvolvimento de um
programa de computador que efetue a leitura de dois valores numéricos;
efetue em seguida as quatro operações matemáticas (processamento
matemático) dos valores lidos e apresente como saída os resultados
obtidos. Para tanto, considere o seguinte código:
-- programa cap0201.lua
   io.write("Entre o 1o. valor: ") A = io.read("*number")
   io.write("Entre o 2o. valor: ") B = io.read("*number")
 
   X1 = A + B
   X2 = A - B
   X3 = A * B
   X4 = A / B
 
   io.write("Adicao .........: ", X1, "\n")
   io.write("Subtracao ......: ", X2, "\n")
   io.write("Multiplicacao ..: ", X3, "\n")
   io.write("Divisao ........: ", X4, "\n")
Em seguida, escreva o código do programa anterior em um editor de texto
de sua preferência, gravando-o com o nome cap0201.lua dentro da pasta
(diretório) de trabalho de seu computador.
As instruções do programa com o uso de io.read() estão sendo usadas
para efetivarem a ação de entrada dos valores numéricos a que serão
fornecidas as variáveis A e B. Note que, para efetivar a entrada de dados,
está em uso o comando io.read() com o parâmetro *number entre aspas
informando que o conteúdo a ser armazenado na variável é um dado de
tipo numérico que poderá ser do tipo inteiro ou do tipo real. Se o
parâmetro *number for omitido, o interpretador entenderá que a entrada de
dados é um valor alfanumérico. Além do parâmetro *number, pode-se
também usar os parâmetros *all para realizar a leitura de um arquivo
inteiro em uso ou *line para fazer a leitura da próxima linha de um
arquivo em uso. Nesta etapa de aprendizagem, será concentrado o estudo
apenas sobre o parâmetro *number.
No trecho do código em que são de nidas as atribuições para as variáveis
X1, X2, X3 e X4, há o estabelecimento das ações de processamento
matemático, as quais efetuam as operações dos valores armazenados nas
variáveis A e B realizando as atribuições dos resultados obtidos junto às
variáveis X1, X2, X3 e X4.
Após a ação de processamento, o programa efetua a saída dos conteúdos
armazenados nas variáveis Xs. Note que, além da indicação das variáveis
Xs, a saída realizada por io.write() usa a de nição da sequência de escape
\n A m de avançar uma linha em branco após a apresentação da saída do
dado indicado.
Observe no programa as ações de entrada, processamento e saída. Depois
de efetuar a gravação do programa cap0201.lua, proceda com sua execução
a partir da seguinte linha de comando.
lua53 cap0201.lua (no MS-Windows)
./lua53 cap0201.lua (no MacOS X ou Linux)
Perceba que, ao se executar o programa, é apresentado um cursor
piscando na tela após a apresentação da primeira mensagem. Nesse
momento, forneça o primeiro valor numérico e acione <Enter>.
Novamente é apresentado o cursor piscando após a segunda mensagem.
Entre um segundo valor e acione <Enter>. Perceba em seguida a
apresentação dos resultados.
A m de exempli car o uso da funcionalidade print(), proceda com a
alteração indicada em negrito do código seguinte e grave a nova versão do
programa com o nome cap0202.lua na pasta de trabalho do computador
em uso.
-- programa cap0202.lua
   io.write("Entre o 1o. valor: ") A = io.read("*number")
   io.write("Entre o 2o. valor: ") B = io.read("*number")
 
   X1 = A + B
   X2 = A - B
   X3 = A * B
   X4 = A / B
 
   print("Adicao .........: " .. X1)
   print("Subtracao ......: " .. X2)
   print("Multiplicacao ..: " .. X3)
   print("Divisao ........: " .. X4)
Após a execução do programa, note a apresentação da mensagem de saída
por meio do comando print(), que efetua o salto automático da linha. O
uso do operador de concatenação garante que não sejam apresentados
espaços em branco entre a mensagem e o valor de saída.
A seguir é desenvolvido um programa que calcula o salário líquido de um
pro ssional que trabalha por hora. Para montar o programa, é preciso
saber alguns dados, como: valor da hora de trabalho, número de horas
trabalhadas no mês e o percentual de desconto da assistência médica. O
programa deve apresentar os valores do salário bruto, do valor descontado
e o salário líquido. Observe o programa cap0203.lua e atente para os
trechos grafados em negrito, os quais demonstram as ações de entrada e
saída.
-- programa cap0203.lua
   io.write("Entre as horas trabalhadas ......: ")
   HT = io.read("*number")
 
   io.write("Entre o valor da hora ...........: ")
   VH = io.read("*number")
 
   io.write("Entre o percentual de desconto ..: ")
   PD = io.read("*number")
 
   SB = HT * VH
   TD = (PD/100) * SB
   SL = SB - TD
 
   io.write("Salario bruto ...: ", SB, "\n")
   io.write("Desconto ........: ", TD, "\n")
   io.write("Salario liquido .: ", SL, "\n")
Execute o programa cap0203.lua e forneça os dados solicitados. Observe
que será preciso melhorar a visualização da saída dos dados numéricos.
Para tanto, será utilizada junto às instruções de saída a função
string.format() com a formatação dos valores numéricos com o formato
7:2.
O formato 7:2 determina 7 posições para a representação de um valor
numérico do tipo real (ponto utuante) das quais 2 posições serão usadas
para a representação dos valores das casas decimais, além de um espaço
para a apresentação do ponto decimal. Assim, o formato 7:2 determina
como máscara de representação numérica a forma 9999.99.
A seguir, efetue no código do programa cap0203.lua as alterações
indicadas em seguida no trecho de código relacionado à ação de saída do
programa e grave essas modi cações no arquivo cap0204.lua.
io.write("Salario bruto ...: ")
io.write(string.format("%7.2f", SB), "\n")
io.write("Desconto ........: ")
io.write(string.format("%7.2f", TD), "\n")
io.write("Salario liquido .: ")
io.write(string.format("%7.2f", SL), "\n")
O primeiro valor da formatação, no caso 7, corresponde ao tamanho total
de posições de um número do tipo ponto utuante e seu ponto utuante;
o segundo valor, nesse caso 2, corresponde ao número de casas decimais
após o ponto (também chamada mantissa).
Observe que, para formatar a saída numérica com ponto utuante, foi
utilizado o formato %TOTAL.MANTISSAf, em que TOTAL é a de nição do total
de posições a serem utilizadas (expoente + ponto + mantissa), e MANTISSA é
a de nição da quantidade de casas decimais a serem utilizadas. O código
f é usado para de nir a formatação de valores em ponto utuante. Caso
queira formatar uma saída numérica para valores inteiros, basta utilizar o
formato %TOTALd, sendo TOTAL a de nição do tamanho numérico a ser
usado e o código d usado para de nir a apresentação de valores inteiros,
que são valores decimais.
Além das formatações apresentadas, é possível fazer a de nição de outros
formatos, por exemplo pelo uso de alguns formatadores como: "%s" string;
"%q" string com delimitadores; "%c" caractere; "%d" inteiro com sinal; "%i"
igual a "%d"; "%u" inteiro sem sinal; "%o" inteiro octal; "%x" hexadecimal
usando letras minúsculas (abcdef); %X hexadecimal usando letras
maiúsculas (ABCDEF); "%f" real no formato posições.mantissa; "%g" ou
"%g" real no formato inteiro sem casas decimais; "%e" real no formato
exponencial com “e” minúsculo e "%E" real no formato exponencial com
“E” maiúsculo, como:
FMT = string.format
 
print(FMT("%s", "Texto")) -- mostra: Texto
print(FMT("%q", "Texto")) -- mostra: "Texto"
print(FMT("%c", 65)) -- mostra: A
print(FMT("%e", math.pi)) -- mostra: 3.141593e+000
print(FMT("%E", math.pi)) -- mostra: 3.141593E+000
print(FMT("%d", 5)) -- mostra: 5 (numero formato decimal)
print(FMT("%i", 5)) -- mostra: 5 (numero formato inteiro)
print(FMT("%u", -1)) -- mostra: 18446744073709551615
print(FMT("%2d", 5)) -- mostra: 5 (alinhado a direita)
print(FMT("%02d", 5)) -- mostra: 05
print(FMT("%o", 10)) -- mostra: 12 (10 em oct)
print(FMT("%x", 10)) -- mostra: a (10 em hex)
print(FMT("%X", 10)) -- mostra: A (10 em hex)
print(FMT("%5.2f", 10.5)) -- mostra: 10.50
print(FMT("%5.2g", 10.5)) -- mostra: 10
print(FMT("%5.2G", 10.5)) -- mostra: 10
Dentro do escopo de operação com entrada, processamento e saída, pode-
se efetuar, além de operações aritméticas, operações com concatenação de
sequências de caracteres.
As operações com concatenações são feitas exclusivamente com dados do
tipo sequências de caracteres na formação de strings. Nesse caso, se algum
valor numérico for utilizado, será automaticamente considerado caractere,
como se pode constatar no programa seguinte:
-- programa cap0205.lua
   print("Linguagem " .. "Lua")
   print(1 .. 2)
   print("Lua " .. 2018)
Escreva o programa gravando-o com o nome cap0205.lua e faça sua
execução como orientado.

2.4 Entrada alternativa de dados


A forma de execução de entrada de dados na linguagem Lua tradicional e
popularmente encontrada é realizada pela instrução io.read("*number").
No entanto, essa ação pode ser executada com o uso de uma função de
conversão numérica denominada tonumber() em conjunto com io.read().
A m de demonstrar o uso de tonumber(), considere como exemplo um
programa que efetue a leitura de um valor numérico qualquer e apresente
como resultado o valor de seu quadrado. Para tanto, considere o seguinte
código:
-- programa cap0206.lua
   io.write("Entre um valor: ")
   N = tonumber(io.read())
 
   X = N ^ 2
   print(N .. " ^ 2 = " .. X)
Em seguida, escreva o código de programa e grave-o com o nome
cap0206.lua. Note que essa é uma maneira alternativa de se fazer a entrada
de dados e realizar a conversão da entrada (sempre realizada como
alfanumérica) para um dado do tipo numérico. A instrução de entrada N =
tonumber(io.read()) também pode ser escrita com a indicação explícita de
uso da sua biblioteca operacional stdin (entrada padrão), sendo N =
tonumber(io.stdin:read()).

2.5 De nição de pausa


A realização da ação de pausa na execução de um programa escrito na
linguagem Lua que aguarde o acionamento da tecla <Enter> pode ser
de nida com a instrução io.read '*l', desde que seja usada
anteriormente a função tonumber() para efetivar a entrada de dados
numéricos. Nesse sentido, o programa a seguir demonstra o cálculo da
adição de dois valores e, depois de mostrar o resultado, aguarda o
acionamento da tecla <Enter> para o encerramento do programa.
-- programa cap0207.lua
   io.write("Entre o 1o. valor: ")
   A = tonumber(io.read())
 
   io.write("Entre o 2o. valor: ")
   B = tonumber(io.read())
 
   X = A + B
 
   io.write("Adicao = ", X, "\n\n")
 
   io.write("Tecla <Enter> para encerrar...")
   io.read('*l')
Em seguida, escreva o código de programa atribuindo-lhe o nome
cap0206.lua e faça sua execução atentando para o momento em que a
mensagem "Acione <Enter> para encerrar..." é apresentada e quando a
tecla <Enter> é acionada, momento em que o programa é nalizado.
O parâmetro “*l” de nido para a funcionalidade io.read() tem por
nalidade efetuar a leitura de uma linha ignorando a ação de m da linha
quando nenhum parâmetro é dado. Dessa forma, com esse recurso é
possível estabelecer uma ação de pausa temporária que espera a entrada
de algum dado que, nesse caso, não é fornecido além do uso da tecla
<Enter>.
A forma escrita io.read('*l') pode ser também de nida como io.read
'*l', sem o uso dos parênteses, como serão aplicados em diversos
programas desta obra. O parâmetro "*l" é um modo reduzido de uso do
parâmetro *line.
A forma de uso da funcionalidade io.read() aceita, além do parâmetro
"*l", os parâmetros "*n" para a leitura de um valor numérico como
substituto do parâmetro *number, e o parâmetro "*a" substituto do
parâmetro *all é usado para estabelecer a leitura do bu er de um arquivo.
A funcionalidade io.read() pode ser usada para a entrada limitada de
caracteres ao se especi car como seu parâmetro um valor limitante. Por
exemplo, a instrução io.read(8) determina que apenas 8 caracteres são
aceitos na entrada desprezando-se os demais fornecidos.

2.6 Compilação de programas


Apesar de Lua ser uma linguagem do tipo script, e por essa razão poder
ser interpretada, ela possui um compilador que gera um código binário
no formato bytecode e pode ser executado posteriormente pelo próprio
interpretador. Para usar esse recurso, é necessário utilizar o programa luac
como segue:
luac53 <opções> <prog.lua>
O parâmetro opções é opcional, podendo ser omitido; o parâmetro
obrigatório prog.lua é a indicação de um código de script Lua que será
compilado.
Em opções, podem-se utilizar algumas chaves de execução, destacando-se
principalmente:
• -l gera listagem dos bytecodes do programa compilado.
• -o arquivo usado para de nir o nome do arquivo do programa
compilado (arquivo de saída). Se omitida essa opção, o programa
compilado será de nido com o nome luac.out.
• -v apresenta a informação da versão do ambiente Lua.
Um programa compilado em Lua não possui maior velocidade de
execução se comparado a sua versão no formato script, pois, quando se
indica a execução do script Lua com o interpretador, este faz
automaticamente uma pré-compilação do código.
Outro detalhe operacional é o fato de o compilador gerar um único
arquivo de saída, mesmo que haja um conjunto de scripts a serem
executados.
A m de proceder a um teste simpli cado de execução do compilador,
informe na linha de comando de seu sistema a instrução:
luac53 prog.lua
Em seguida, execute o programa compilado com a instrução:
lua53 luac.out
Para conferir que o arquivo gerado pelo compilador é binário, tente abrir
com um editor de texto simples o arquivo luac.out.
Para gerar um arquivo compilado com nome de nido pelo programador,
execute a instrução:
luac53 –o teste.cmp prog.lua
Em seguida, execute o programa com a instrução:
lua53 teste.cmp
Observe a instrução para listar a estrutura de bytecodes usados pelo
compilador:
luac53 –l prog.lua
Após a execução da instrução anterior, a listagem é imediatamente
apresentada.
A vantagem no uso de scripts compilados é a possibilidade de o cliente
não ter acesso ao código-fonte do programa (script), a menos que seja essa
a intenção do programador.
A propósito, para os próximos capítulos não serão mais indicadas as
orientações de edição, gravação e execução dos programas, considerando-
se que essas serão ações subentendidas para uso pelo leitor.

2.7 Exercícios de xação


Desenvolver os programas elencados de 1 até 11, cando a cargo do
professor selecionar a ordem e os problemas a serem resolvidos.
1. Ler uma temperatura em graus Celsius e apresentá-la convertida em
graus Fahrenheit. A fórmula de conversão é F = (9 * C + 160) / 5,
sendo F a temperatura em Fahrenheit e C a temperatura em Celsius.
2. Ler uma temperatura em graus Fahrenheit e apresentá-la convertida
em graus Celsius. A fórmula de conversão é C = ((F - 32) * 5) / 9, sendo
F a temperatura em Fahrenheit e C a temperatura em Celsius.
3. Ler dois valores para as variáveis A e B e efetuar a troca dos valores de
modo que a variável A passe a possuir o valor da variável B e a variável
B passe a possuir o valor da variável A. Apresentar os valores após a
efetivação do processamento da troca.
4. Elaborar programa que calcule e apresente o valor do volume de uma
caixa retangular utilizando a fórmula VOLUME = COMPRIMENTO *
LARGURA * ALTURA.
5. Efetuar a leitura de um valor numérico e apresentar o resultado do
valor lido elevado ao quadrado.
6. Ler dois valores numéricos, variáveis A e B, e apresentar o resultado
do quadrado da diferença do primeiro valor (variável A) em relação ao
segundo valor (variável B).
7. Construir programa que leia três valores numéricos, variáveis A, B e
C, e apresente como resultado o valor da soma dos quadrados dos
valores lidos.
8. Construir um programa que leia três valores numéricos, variáveis A, B
e C, e apresente como resultado o valor do quadrado da soma dos três
valores lidos.
9. Elaborar programa que calcule e apresente o valor do resultado da
área de uma circunferência (variável VOL). O programa deve solicitar a
entrada do valor do raio da circunferência (variável R). Para a execução
desse problema, utilize a fórmula VOL = math.pi + R ^ 2.
10. Elaborar programa que leia dois valores numéricos desconhecidos
representados pelas variáveis A e B. Calcular e apresentar os resultados
das quatro operações aritméticas básicas.
11. Elaborar programa que calcule uma raiz de base qualquer com
índice qualquer.
CAPÍTULO 3

Programação com decisão

Este capítulo apresenta o uso do princípio de tomada de decisões. São


indicadas as técnicas de programação com: condição, decisão, operadores
relacionais e lógicos, desvio condicional simples, desvio condicional
composto, desvio incondicional, desvio seletivo simulado com ação
incondicional e divisibilidade.

3.1 Condição, decisão e operadores relacionais


Decisão é o ato de deliberar, de julgar, de tomar uma decisão, de decidir.
Para que uma decisão seja tomada, é preciso que esta esteja calcada em
uma proposição, ou seja, uma condição que, do ponto de vista da ciência
da computação, é a relação lógica entre os elementos que formam a
proposição (condição) para a tomada de uma decisão cuja resposta
poderá ser verdadeira ou falsa.
Do ponto de vista computacional, pode-se considerar decisão a ação
lógica que conduz a uma escolha a partir da de nição de certa condição,
sendo esta a relação lógica estabelecida entre dois e somente dois
elementos passíveis de avaliação, podendo-se avaliar as relações de
variáveis com variáveis e de variáveis com constantes, considerando-se
que constante pode ser a de nição de qualquer valor.
A relação lógica existente entre os elementos de uma condição é obtida
com a utilização dos operadores relacionais, de acordo com a Tabela 3.1.
Tabela 3.1 – Operadores relacionais
Símbolo Signi cado

== Igual a
Símbolo Signi cado

~= Diferente de

> Maior que

< Menor que

>= Maior ou igual que

<= Menor ou igual que

3.2 Desvios condicionais


O desvio condicional está associado à utilização de decisões em um
programa. A resposta a uma decisão pode ser verdadeira ou falsa. Se
verdadeira, executará certa ação; se falsa, executará outra. Um desvio
condicional pode ser simples, composto ou sequencial.

3.2.1 Desvio condicional simples


Desvio condicional simples ocorre quando houver uma condição que
desvia a execução do programa caso o resultado lógico avaliado da
condição seja verdadeiro. Se o resultado lógico for falso, nada acontecerá,
e o programa simplesmente segue o seu uxo de execução.
Na linguagem de programação Lua, um desvio condicional simples é
de nido por meio da instrução if, que possui a seguinte sintaxe:
if (condição) then
   bloco de ação executado se a condição for verdadeira
end
Se condição for verdadeira, então serão executadas todas as instruções
de nidas na área de bloco de ação delimitada entre as instruções if e end.
Se condição for falsa, o bloco de ação não será executado, transferindo a
execução do programa para após a instrução end.
Para exempli car esse tipo de ação, o programa cap0301.lua efetua a
leitura de dois valores inteiros, e os apresenta em ordem crescente. Para
tanto, considere o seguinte código:
-- programa cap0301.lua
   io.write("Entre 1o. valor: ") A = tonumber(io.read())
   io.write("Entre 2o. valor: ") B = tonumber(io.read())
 
   if (A > B) then
     A, B = B, A
   end
 
   io.write("Os valores sao: ") print(A .. " e " .. B)
 
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
O uso dos pontos duplos junto à linha de saída print(A .. " e " .. B)
caracteriza-se por efetuar uma ação de concatenação entre os valores das
variáveis e do texto com o conectivo “e”.

3.2.2 Desvio condicional composto


Anteriormente, foi visto como usar a instrução if simples para avaliar
determinada condição (desvio condicional simples). Agora, será explicado
como usar a instrução if... else.
Numa instrução if... else, se a condição for verdadeira, será executada a
instrução posicionada entre as instruções if e else. Sendo a condição falsa,
será executada a instrução posicionada logo após a else, como indicado
na seguinte sintaxe:
if (condição) then
   bloco de ação executado se a condição for verdadeira
else
   bloco de ação executado se a condição for falsa
end
A m de exempli car esse tipo de ação, o programa cap0302.lua efetua a
leitura de duas notas escolares, calcula a média aritmética das notas e
apresenta a mensagem Aprovado caso a condição seja maior ou igual a 5. Se
a condição for menor que 5, apresenta a mensagem Reprovado. Junto de
cada mensagem será apresentado o valor da média.
-- programa cap0302.lua
   io.write("Entre 1a. nota: ") N1 = tonumber(io.read())
   io.write("Entre 2a. nota: ") N2 = tonumber(io.read())
 
   MD = (N1 + N2) / 2
 
   if (MD >= 5) then
      io.write("Aprovado, ")
   else
      io.write("Reprovado, ")
   end
 
   print(string.format("%5.2f", MD))
 
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, informe os valores de duas notas que
resultem valores de média acima e abaixo do valor da média para
visualizar a apresentação das mensagens correspondentes de aprovação e
reprovação.

3.3 Operadores lógicos


Quando houver a necessidade de se trabalhar com o relacionamento de
duas ou mais condições ao mesmo tempo para a tomada de uma única
decisão, torna-se necessário o uso de operadores lógicos.
Os operadores lógicos na linguagem Lua são três: and (conjunção), or
(disjunção) e not (negação), tendo como prioridade de execução a ordem:
not, and ou or. Os operadores lógicos and e or podem fornecer como
resposta lógica o valor true quando a condição é verdadeira ou os valores
false (falso) ou nil (zero) quando a condição for falsa. Em relação ao
operador lógico, not retorna como resposta os valores false (falso) ou true
(verdadeiro).
O operador lógico de conjunção é utilizado quando duas ou mais
relações lógicas devem ser verdadeiras, nesse caso nil em Lua, caso
contrário, o resultado do valor lógico retornado será falso. Observe a
Tabela 3.2.
Tabela 3.2 – Operador lógico “and”
Condição 1 Condição 2 Resultado

Falsa Falsa Falso

Verdadeira Falsa Falso

Falsa Verdadeira Falso

Verdadeira Verdadeira Verdadeiro

O operador and faz com que o resultado lógico seja verdadeiro (nil)
quando todas as condições envolvidas na decisão também o forem,
gerando assim um resultado lógico verdadeiro.
A m de exempli car esse tipo de ação, o programa cap0303.lua efetua a
leitura de um valor numérico entre 1 e 9 e apresenta mensagem
informando se o valor está na faixa de 1 a 9 ou se está fora dessa faixa de
valores.
-- programa cap0303.lua
   io.write("Entre numero: ") N = tonumber(io.read())
 
   if (N >= 1) and (N <= 9) then
      print("Valor na faixa de 1 a 9")
   else
      print("Valor fora da faixa")
   end
 
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
O exemplo anterior apresenta a utilização do operador de conjunção and,
que somente permitirá a apresentação da mensagem: Valor na faixa de 1
a 9, caso o valor fornecido para a variável N esteja entre 1 e 9. Qualquer
valor fornecido fora da faixa de nida apresentará a mensagem: “Valor
fora da faixa".
O operador lógico de disjunção (inclusiva) é usado quando pelo menos
um dos relacionamentos lógicos de uma decisão precisa ser verdadeiro
(nil) para obter-se um resultado lógico verdadeiro (nil); caso contrário, o
valor do resultado lógico retornado será false. Observe a Tabela 3.3.
Tabela 3.3 – Operador lógico “or”
Condição 1 Condição 2 Resultado

Falsa Falsa Falso

Verdadeira Falsa Verdadeiro

Falsa Verdadeira Verdadeiro

Verdadeira Verdadeira Verdadeiro

O operador or faz com que o resultado lógico seja verdadeiro (nil)


quando pelo menos uma das condições envolvidas na decisão for
verdadeira (nil), fornecendo um resultado lógico verdadeiro.
Para exempli car esse tipo de ação, o programa cap0304.lua efetua a
leitura do sexo biológico de um ser humano e apresenta mensagem
informando se o sexo fornecido é ou não válido.
-- programa cap0304.lua
   io.write("Entre seu sexo: ") S = io.read()
 
   if (S == "m") or (S == "f") then
      print("Sexo valido")
   else
      print("Sexo inválido")
   end
 
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
O exemplo anterior mostra a utilização do operador lógico or, que
somente permite a apresentação da mensagem “Sexo válido", caso o valor
fornecido para a variável S seja "m" ou "f". Qualquer outro valor fornecido
apresentará a mensagem “Sexo inválido".
O operador lógico de negação é utilizado quando se necessita estabelecer
a inversão do valor de um determinado resultado lógico de uma decisão.
É possível obter valores: não verdadeiro e não falso. O operador lógico not
inverte o resultado lógico de uma condição. Observe a Tabela 3.4.
Tabela 3.4 – Operador lógico “not”
Condição Resultado

Verdadeira Não verdadeira

Falsa Não falsa

O operador not faz com o resultado lógico de uma determinada decisão


seja invertido.
A m de exempli car esse tipo de ação, o programa cap0305.lua efetua a
leitura de um valor numérico e apresenta o valor informado caso este não
seja menor que 3, isto é, apresenta somente os valores que estejam acima
do número 3. Observe o código seguinte.
-- programa cap0305.lua
   io.write("Entre um numero: ") N = tonumber(io.read())
 
   if not (N <= 3) then
      print(N)
   end
 
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, serão apresentados os valores fornecidos
que não sejam menores ou iguais a 3, isto é, qualquer valor acima de 4.
A linguagem Lua, assim como outras linguagens de programação, não
possui o operador lógico de disjunção exclusiva (xor). Essa ausência pode
criar um pequeno transtorno para quem necessita dessa funcionalidade, a
menos que seja utilizada a expressão lógica:
(Cond1 and not (Cond2)) or (not (Cond1) and Cond2)

3.4 Outros desvios


Desvios condicionais baseados em tomada de decisão possibilitam criar
várias formas de desvios por meio dos conceitos anteriormente
apresentados, podendo ser: decisão simples e/ou decisão composta.
Assim sendo, podem ser utilizadas relações de tomadas de decisão
aninhadas ou sequenciais.

3.4.1 Desvio condicional encadeado


Para demonstrar o uso de operadores lógicos em exemplo mais complexo,
considere a necessidade de desenvolver um programa que leia três valores
para os lados A, B e C de um triângulo. Esse programa deve veri car se os
lados fornecidos formam realmente um triângulo. Se essa condição for
verdadeira, deve ser indicado o tipo de triângulo formado: isósceles,
escaleno ou equilátero. É preciso considerar que triângulo é uma forma
geométrica (polígono) composta de três lados, e cada lado é menor que a
soma dos outros dois lados, ou seja, será um triângulo quando A < B+C,
quando B < A+C e quando C < A+B.
Tendo certeza de que os valores informados formam um triângulo, basta
saber o seu tipo (isósceles, escaleno ou equilátero). Para tanto, deve-se
considerar que um triângulo é isósceles quando possui dois lados iguais e
um diferente, sendo A=B ou A=C ou B=C; é escaleno quando todos os lados
são diferentes, sendo A<>B e B<>C; e é equilátero quando todos os lados são
iguais, sendo A=B e B=C. Assim sendo, considere o programa cap0306.lua.
-- programa cap0306.lua
   io.write("Entre o lado <A>: ") A = tonumber(io.read())
   io.write("Entre o lado <B>: ") B = tonumber(io.read())
   io.write("Entre o lado <C>: ") C = tonumber(io.read())
 
   if (A < B + C) and (B < A + C) and (C < A + B) then
      if (A == B) and (B == C) then
         print("Triangulo equilátero.")
      else
         if (A == B) or (A == C) or (C == B) then
            print("Triangulo isosceles.")
         else
            print("Triangulo escaleno.")
         end
      end
   else
      print("Os valores fornecidos nao formam um triangulo.")
   end
 
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Esse exemplo demonstra, com a utilização dos operadores lógicos, a
capacidade de um programa de nir se os valores fornecidos formam
realmente um triângulo.
Se a condição for verdadeira, esse programa indica o tipo de triângulo
formado. Se forem fornecidos, respectivamente, os valores 8, 2 e 3 para os
lados, representados pelas variáveis A, B e C, aparece a mensagem "Os
valores fornecidos nao formam um triangulo", pois a primeira condição if
(A < B + C) and (B < A + C) and (C < A + B) then resulta no valor lógico
falso, uma vez que 8 é maior que a soma de 2 e 3.
Caso sejam fornecidos os valores 8, 8 e 2, a primeira instrução if será
verdadeira, indicando que os lados fornecidos formam um triângulo.
Apesar de o lado A ser igual ao lado B, mas este não ser igual ao lado C, o
triângulo formado não é equilátero. A segunda instrução if tem seu
resultado lógico como falso, sobrando a veri cação da condição para a
terceira instrução if, que indica o triângulo como isósceles, pois o lado A
é igual ao lado B.

3.4.2 Desvio condicional sequencial


Para demonstrar o uso de desvios condicionais sequenciais, será criado
um programa que simula uma simples calculadora, que faz a leitura de
apenas dois valores. O usuário escolhe a operação, e o programa
apresenta o resultado da operação escolhida. Assim, considere o
programa cap0307.lua.
-- programa cap0307.lua
   io.write("Entre o valor <A>: ") A = tonumber(io.read())
   io.write("Entre o valor <B>: ") B = tonumber(io.read())
   print()
   print("[1] - Adicao")
   print("[2] - Subtracao")
   print("[3] - Multiplicacao")
   print("[4] - Divisao")
   print()
   io.write("Escolha uma opca: ") OPCAO = tonumber(io.read())
 
   if (OPCAO >= 1) and (OPCAO <= 4) then
      if (OPCAO == 1) then
         R = A + B;
         print(string.format("\nResultado = %.2f", R) .. ".\n")
      end
      if (OPCAO == 2) then
         R = A - B;
         print(string.format("\nResultado = %.2f", R) .. ".\n")
      end
      if (OPCAO == 3) then
         R = A * B;
         print(string.format("\nResultado = %.2f", R) .. ".\n")
      end
      if (OPCAO == 4) then
         if (B == 0) then
            print("\nResultado = Erro.\n")
         else
            R = A / B
            print(string.format("\nResultado = %.2f", R) .. ".\n")
         end
      end
   else
      print("\nOpcao invalida.\n")
   end
 
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Execute alguns testes com valores inteiros e pontos utuantes. Na decisão
if (OPCAO == 4) then, encontra-se uma segunda decisão encadeada,
veri cando se o valor da variável B é 0 (zero). Sendo essa condição
verdadeira, é apresentada mensagem de erro.
O programa possui a veri cação da validade da opção fornecida no
menu. Nesse caso, se for fornecido um valor abaixo de 1 ou acima de 4
como ação de erro, será apresentada mensagem indicando que a opção é
inválida.

3.4.3 Desvio condicional sobreposto


Até a versão utilizada para a elaboração deste livro, a linguagem Lua não
possuía um comando que gerenciasse uma estrutura de controle seletivo
como o comando switch da linguagem C. No entanto, possui a
possibilidade de estabelecer o uso de condições sobrepostas a partir do
comando elseif que simulam em parte o uso da ação de controle seletivo,
a partir da sintaxe:
if (condição1) then
   bloco de ação 1
elseif (condição2) then
   bloco de ação 2
elseif (condiçãoN) then
   bloco de ação N
else
   bloco de ação N + 1
end
Se condição1 for verdadeira, então serão executadas as instruções
posicionadas na área de bloco de ação entre if (condição1) then e elseif
(condição2) then, ou seja, as instruções que estiverem de nidas no bloco
de ação 1. Se condição2 verdadeira, serão executadas as instruções que
estiverem posicionadas na área de bloco de ação entre if (condição2) then
e elseif (condiçãoN) then e assim por diante. Não havendo condições
verdadeiras, serão executadas as instruções entre else e end de nidas no
bloco de ação N + 1.
O programa cap0308.lua efetua a leitura de um valor numérico inteiro
entre 1 e 12 que correspondem ao nome do mês do ano de um calendário
e exibe o nome do mês solicitado.
-- programa cap0308.lua
   io.write("Entre valor: ")
   N = tonumber(io.read())
 
   if (N == 1) then
      print("Janeiro")
   elseif (N == 2) then
      print("Fevereiro")
   elseif (N == 3) then
      print("Marco")
   elseif (N == 4) then
      print("Abril")
   elseif (N == 5) then
      print("Maio")
   elseif (N == 6) then
      print("Junho")
   elseif (N == 7) then
      print("Julho")
   elseif (N == 8) then
      print("Agosto")
   elseif (N == 9) then
      print("Setembro")
   elseif (N == 10) then
      print("Outubro")
   elseif (N == 11) then
      print("Novembro")
   elseif (N == 12) then
      print("Dezembro")
   else
      print("Mes invalido")
   end
 
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, forneça tanto valores válidos como
inválidos para veri car todas as possibilidades do recurso elseif.

3.5 Desvio seletivo simulado com ação incondicional


A partir da versão 5.2.0-beta-rc1, a linguagem Lua incorporou o comando
goto que despertou diversas críticas por parte dos programadores mais
ortodoxos. No entanto, o problema não é o comando em si, mas como ele
é usado de maneira inadequada por programadores inexperientes. Sendo
este um livro de Lua, não é possível omitir tal funcionalidade, assim, para
conhecer exemplos de bom uso do comando goto, visite o site http://lua-
users.org/wiki/GotoStatement.
A m de demonstrar o uso adequado (bem comportado) para o comando
goto na linguagem Lua, considere a possibilidade de criar uma estrutura
de seleção que simule um desvio condicional com decisão seletiva,
semelhante ao comando switch da linguagem C.
O comando goto efetua um desvio incondicional para certo ponto do
código de programa a partir da de nição de um rótulo de conexão. Dessa
forma, esse comando pode ser usado a partir da sintaxe:
::rótulo::
 
goto rótulo
Em que a indicação rótulo se refere ao ponto de conexão que receberá a
ação do desvio imputado. Para demonstrar o uso de uma estrutura
simulada de decisão seletiva, considere como exemplo o programa
cap0309.lua, que efetua ação semelhante ao programa cap0308.lua.
-- programa cap0309.lua
   io.write("Entre valor: ")
   N = tonumber(io.read())
 
   if (N == 1) then print("Janeiro") goto fim end
   if (N == 2) then print("Fevereiro") goto fim end
   if (N == 3) then print("Marco") goto fim end
   if (N == 4) then print("Abril") goto fim end
   if (N == 5) then print("Maio") goto fim end
   if (N == 6) then print("Junho") goto fim end
   if (N == 7) then print("Julho") goto fim end
   if (N == 8) then print("Agosto") goto fim end
   if (N == 9) then print("Setembro") goto fim end
   if (N == 10) then print("Outubro") goto fim end
   if (N == 11) then print("Novembro") goto fim end
   if (N == 12) then print("Dezembro") goto fim
   else
      print("Mes invalido")
   end
 
   ::fim::
 
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao executar o programa cap0309.lua, os resultados apresentados serão os
mesmos indicados pelo programa cap0308.lua.

3.6 Divisibilidade
Divisibilidade é a qualidade do que é divisível. Nesse contexto, dois
conceitos devem ser conhecidos e entendidos pelos programadores de
computador: múltiplos e divisores de números naturais. Entende-se por
número natural um valor numérico que seja inteiro e positivo.
Múltiplos são os resultados obtidos da multiplicação de dois números
naturais, enquanto divisores são números naturais que dividem outros
números naturais para gerar um resultado exato de divisão, ou seja, obter
resto de divisão sempre zero. Quando o resto de uma divisão de números
naturais é igual a zero, tem-se divisibilidade, ou seja, resultado de divisão
exata.
Pelo fato de todo número natural ser múltiplo de si mesmo, um modo de
trabalhar esses valores é por meio das operações de cálculo com divisores.
Em uma divisão, existem alguns termos que devem ser conhecidos:
dividendo (valor que será dividido), divisor (valor que divide o
dividendo), quociente (resultado da divisão do dividendo pelo divisor) e
resto (valor que sobra da divisão).
Do ponto de vista computacional, de acordo com a sintaxe da linguagem
Lua, a obtenção do resultado de divisibilidade de um valor é
operacionalizada a partir do operador aritmético de resto de divisão “%”
ou a partir da operação math.mod().
A título de demonstração do processo de divisibilidade, considere o
programa que efetua a leitura de um valor numérico e apresenta esse
valor caso seja divisível por 4 e 5. Não sendo divisível por 4 e 5, o
programa deve apresentar a mensagem “Valor não é divisível por 4 e 5".
Para resolver esse problema, é necessário, além do operador lógico and,
veri car se a condição do valor lido é ou não divisível por 4 e 5.
O programa proposto é de nido com base em duas soluções, sendo: a
primeira versão a partir do cálculo direto do resto de divisão com a
expressão resto = dividendo - divisor * (divisor // dividendo) e a
segunda versão a partir do cálculo do resto de divisão com o operador
aritmético de resto de divisão resto = dividendo % divisor. Fica a critério
do programador escolher a desejada.
O programa cap0310.lua demonstra a veri cação da ação de divisibilidade
com o uso do cálculo genérico de obtenção de resto de divisão.
-- programa cap0310.lua
   io.write("Entre valor numerico: ")
   N = tonumber(io.read())
 
   R4 = N - 4 * (N // 4)
   R5 = N - 5 * (N // 5)
 
   if (R4 == 0) and (R5 == 0) then
      print(N)
   else
      print("Valor nao e divisivel por 4 e 5.")
   end
 
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Observe, nesse primeiro exemplo, as expressões aritméticas de cunho
genérico R4 = N - 4 * (N // 4) e R5 = N - 5 * (N // 5), para obtenção do
valor da divisibilidade e do resto da divisão do valor da variável N pelos
valores dos divisores 4 e 5, respectivamente. A instrução de tomada de
decisão usa a condição (R4 == 0) and (R5 == 0), que será verdadeira se
ambas as condições forem verdadeiras.
O programa cap0311.lua demonstra a veri cação da ação de divisibilidade
com o uso do operador de resto “%”.
-- programa cap0311.lua
   io.write("Entre valor numerico: ")
   N = tonumber(io.read())
 
   R4 = N % 4
   R5 = N % 5
 
   if (R4 == 0) and (R5 == 0) then
      print(N)
   else
      print("Valor nao e divisivel por 4 e 5.")
   end
 
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Observe, nesse segundo exemplo, o uso do operador de módulo de
divisão R4 = N % 4 e R5 = N % 5, para obtenção do valor da divisibilidade e
do resto da divisão do valor da variável N pelos valores dos divisores 4 e 5,
respectivamente.

3.7 Exercícios de xação


Desenvolver os programas elencados de 1 até 11 cando a cargo do
professor selecionar a ordem e os problemas a serem resolvidos.
1. Efetuar a leitura de dois valores numéricos representados pelas
variáveis A e B e apresentar o resultado da diferença do maior valor
pelo menor.
2. Realizar a leitura dos valores de quatro notas escolares bimestrais de
um aluno representadas pelas variáveis N1, N2, N3 e N4. Calcular a
média aritmética (variável MD) desse aluno e apresentar a mensagem
“Aprovado com média” se a média obtida for maior ou igual a 5; caso
contrário, apresentar a mensagem “Reprovado com média”. Informar
após a apresentação das mensagens o valor da média obtida pelo
aluno.
3. Ler os valores de quatro notas escolares bimestrais de um aluno,
representadas pelas variáveis N1, N2, N3 e N4. Calcular a média
aritmética (variável MD) desse aluno e apresentar a mensagem
“Aprovado com média” se a média obtida for maior ou igual a 7; caso
contrário, o programa deve solicitar a quinta nota (nota de exame,
representada pela variável NE) do aluno e calcular uma nova média
aritmética (variável MD2) entre a nota de exame e a primeira média
aritmética. Se o valor da nova média for maior ou igual a 5, apresentar
a mensagem “Aprovado em exame com média”; caso contrário,
apresentar a mensagem “Reprovado com média”. Informar também,
após a apresentação das mensagens, o valor da média obtida pelo
aluno.
4. Ler três valores representados pelas variáveis A, B e C e apresentar os
valores lidos dispostos em ordem crescente.
5. Efetuar a leitura de quatro valores numéricos representados pelas
variáveis A, B, C e D. Apresentar apenas os valores que sejam divisíveis
por 2 e 3.
6. Efetuar a leitura de quatro valores numéricos representados pelas
variáveis A, B, C e D. Apresentar apenas os valores que sejam divisíveis
por 2 ou 3.
7. Ler cinco valores numéricos, variáveis A, B, C, D e E, identi car e
apresentar o maior e o menor valores informados, sem que seja feita a
ordenação dos valores.
8. Fazer a leitura de um valor numérico qualquer e apresentá-lo caso
não seja maior que 3. Dica: para a solução desse problema, utilize
apenas o operador lógico de negação.
9. Ler um valor numérico e apresentar uma mensagem informando se o
valor fornecido é par ou ímpar.
10. Efetuar a leitura de um valor numérico que esteja na faixa de valores
de 1 até 9. O programa deve apresentar a mensagem “O valor está na
faixa permitida”, caso o valor informado esteja entre 1 e 9. Se o valor
estiver fora da faixa, o programa deve apresentar a mensagem “O valor
está fora da faixa permitida”.
11. Efetuar a leitura de três valores numéricos desconhecidos
representados pelas variáveis A, B e C. Somar os valores fornecidos e
apresentar o resultado somente se for maior ou igual a 100.
CAPÍTULO 4

Programação com laços

Este capítulo apresenta o uso de laços (loops) para repetição de blocos de


instruções em um programa. É possível com essa técnica de nir
repetições com números variados de vezes, desde laços nitos (quando se
sabe o número de vezes que o laço deve ser executado) até laços
indeterminados (quando não se sabe quantas vezes o laço deve ser
executado).

4.1 Laço pré-teste


O laço pré-teste pode ser executado com uxo condicional falso ou
verdadeiro. Na linguagem Lua, esse tipo de laço é manipulado apenas
pela instrução while, que faz um teste lógico no início do laço, veri cando
se é possível executar o trecho de instruções subordinadas a ele. A forma
padrão para o laço while é a execução com uxo condicional verdadeiro;
caso necessite efetuar um laço condicional com uxo falso, torna-se
necessário o uso do operador lógico not. Esse tipo de laço, devido a sua
característica operacional, pode ser usado para criar laços iterativos e
interativos.
A estrutura de laço while tem seu funcionamento controlado por
condição, sendo possível executar um conjunto de instruções enquanto a
condição veri cada permanecer válida. No momento em que essa
condição não for válida, o processamento da rotina será desviado para
fora do laço. A sintaxe dessa estrutura de laço corresponde a:
while [not] (condição) do
   instruções executadas enquanto a condição for verdadeira
end
instruções executadas após o término do laço
O operador lógico not é opcional e deve ser usado quando se deseja
simular um laço do tipo pré-teste com uxo condicional falso, como o
laço do until... loop encontrado na linguagem de programação
Structured BASIC.

4.1.1 Fluxo condicional verdadeiro


Como exemplo de uso da estrutura de laço pré-teste com uxo
condicional verdadeiro, considere o programa cap0401.lua que mostra o
resultado da tabuada de um número qualquer a partir da ação de um laço
em estilo iterativo. Nesse caso, é necessário de nir um contador para
controlar a apresentação dos resultados da tabuada (um contador de 1 até
10), e, cada vez que o trecho desejado do programa for executado, esse
contador deve ser incrementado com 1.
-- programa cap0401.lua
   io.write("Entre um valor numerico: ")
   N = tonumber(io.read())
   print()
 
   I = 1
   while (I <= 10) do
      R = N * I
      io.write(string.format("%2d", N))
      io.write(" X ")
      io.write(string.format("%2d", I))
      io.write(" = ")
      io.write(string.format("%3d", R), "\n")
      I = I + 1
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Execute o programa algumas vezes e teste diversas entradas com variados
valores para visualizar as diversas tabuadas apresentadas.
Observe que junto à ação de formatação com string.format() estão sendo
de nidos os códigos de formatação "%2d" e "%3d" usados para formatar a
saída numérica de um valor inteiro decimal, daí o código “d” e a
quantidade de posições da direita para a esquerda para o devido
alinhamento numérico do valor.
Agora imagine outra situação: o usuário deseja executar o programa de
tabuada várias vezes, mas não sabe, ao certo, quantas vezes deve repetir o
trecho de programa. Nesse caso, observe o programa cap0402.lua no qual
se faz uso do contexto de aplicação de laço interativo.
-- programa cap0402.lua
   RESP = "S"
   while (string.upper(RESP) == "S") do
 
      io.write("Entre um valor numerico: ")
      N = tonumber(io.read())
      print()
 
      I = 1
      while (I <= 10) do
         R = N * I
         io.write(string.format("%2d", N))
         io.write(" X ")
         io.write(string.format("%2d", I))
         io.write(" = ")
         io.write(string.format("%3d", R), "\n")
         I = I + 1
      end
 
      print()
      print("Novo calculo?")
      io.write("[S] para Sim, outro valor para nao: ")
      RESP = io.read()
      print()
   end
Execute o programa algumas vezes e teste diversas entradas com variados
valores para as tabuadas, mas atente para o momento em que deve
responder “S” para continuar o cálculo ou responder outro caractere para
encerrar a execução do laço interativo.
Observe que nessa versão está em uso a funcionalidade string.upper(),
que converte para o formato maiúsculo o caractere informado junto à
instrução RESP = io.read(). Mesmo que seja fornecido como resposta o
caractere “s”, o programa manterá a execução do laço.

4.1.2 Fluxo condicional falso


Como exemplo de uso de laço pré-teste com uxo condicional falso
(simulado com o operador lógico not), considere o programa cap0403.lua,
que apresenta o resultado da tabuada de um número qualquer. Nesse
caso, é necessário de nir um contador para controlar a apresentação dos
resultados da tabuada (um contador de 1 até 10), e, cada vez que o trecho
desejado do programa for executado, esse contador deve ser incrementado
com 1.
-- programa cap0403.lua
   io.write("Entre um valor numerico: ")
   N = tonumber(io.read())
   print()
 
   I = 1
   while not (I > 10) do
      R = N * I
      io.write(string.format("%2d", N))
      io.write(" X ")
      io.write(string.format("%2d", I))
      io.write(" = ")
      io.write(string.format("%3d", R), "\n")
      I = I + 1
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Execute o programa algumas vezes e teste diversas entradas com variados
valores para visualizar as diversas tabuadas apresentadas. Note que o
efeito do programa cap0403.lua é idêntico ao programa cap0401.lua.

4.2 Laço pós-teste


O laço pós-teste pode ser executado com uxo condicional falso ou
verdadeiro. Na linguagem Lua, esse tipo de laço é manipulado pela
instrução repeat... until, que faz um teste lógico no nal do laço,
veri cando se é possível executar novamente o trecho de instruções
subordinadas a ele. Esse laço tem como característica operacional sempre
executar o bloco subordinado ao laço no mínimo uma vez. A forma
padrão para o laço repeat... until é a execução com uxo condicional
verdadeiro; caso necessite efetuar um laço condicional com uxo falso,
torna-se necessário o uso do operador lógico not. Esse tipo de laço, devido
a sua característica operacional, pode ser usado para criar laços iterativos
e interativos.
A estrutura de laço repeat... until tem seu funcionamento controlado
por condição, mas esse tipo de laço, como dito, executa o bloco de
instruções subordinadas ao laço pelo menos uma vez antes de veri car a
validade da condição estabelecida, diferente do laço pré-teste while, que
executa somente um conjunto de instruções quando a condição for
favorável.
Dessa forma, repeat... until funciona em sentido contrário ao while, pois
sempre processa um conjunto de instruções no mínimo uma vez, mesmo
que a condição não seja válida. A instrução repeat... until pode ser
escrita com a sintaxe:
repeat
   instruções executadas até que a condição [não] seja verdadeira
until [not] (condição)
instruções executadas após o término do laço
O operador lógico not é opcional e deve ser usado quando se deseja
simular um laço do tipo pós-teste com uxo condicional verdadeiro, como
o laço do until... while ou do... while encontrados respectivamente nas
linguagens de programação Structured BASIC e família C.

4.2.1 Fluxo condicional falso


Como exemplo de uso do laço repeat... until, que opera a partir do
uxo de ação falso, considere o programa cap0404.lua que apresente como
resultado a tabuada de um número qualquer.
-- programa cap0404.lua
   io.write("Entre um valor numerico: ")
   N = tonumber(io.read())
   print()
 
   I = 1
   repeat
      R = N * I
      io.write(string.format("%2d", N))
      io.write(" X ")
      io.write(string.format("%2d", I))
      io.write(" = ")
      io.write(string.format("%3d", R), "\n")
      I = I + 1
   until (I > 10)
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Execute o programa e observe que a mudança do laço manteve o mesmo
comportamento de nido de repetições em um estilo de escrita um pouco
diferente.
Levando em consideração a necessidade de executar o programa de
tabuada várias vezes sem saber a quantidade de vezes, observe o código do
programa cap0405.lua no qual se faz uso do contexto de aplicação de laço
interativo.
-- programa cap0405.lua
   repeat
      io.write("Entre um valor numerico: ")
      N = tonumber(io.read())
      print()
 
      I = 1
      repeat
         R = N * I
         io.write(string.format("%2d", N))
         io.write(" X ")
         io.write(string.format("%2d", I))
         io.write(" = ")
         io.write(string.format("%3d", R), "\n")
         I = I + 1
      until (I > 10)
 
      print()
      print("Novo calculo?")
      io.write("[S] para Sim, outro valor para nao: ")
      RESP = io.read()
      print()
   until (string.upper(RESP) ~= "S")
Execute o programa algumas vezes e teste diversas entradas com variados
valores para as tabuadas, mas atente para o momento em que deve
responder “S”, para continuar o cálculo, ou outro caractere, para encerrar a
execução do laço interativo. Note que nesse exemplo não se faz a
inicialização da variável RESP com o valor “S”.

4.2.2 Fluxo condicional verdadeiro


Para exempli car a utilização dessa estrutura de laço de repetição, será
considerado como exemplo o programa de tabuada de um número
utilizado anteriormente. Assim sendo, considere o programa cap0406.lua a
seguir.
-- programa cap0406.lua
   io.write("Entre um valor numerico: ")
   N = tonumber(io.read())
   print()
 
   I = 1
   repeat
      R = N * I
      io.write(string.format("%2d", N))
      io.write(" X ")
      io.write(string.format("%2d", I))
      io.write(" = ")
      io.write(string.format("%3d", R), "\n")
      I = I + 1
   until not (I <= 10)
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Levando em consideração a necessidade de executar o programa de
tabuada várias vezes sem saber a quantidade de vezes por meio da ação de
laço pós-teste interativo, considere o programa cap0407.lua seguinte.
-- programa cap0407.lua
   repeat
      io.write("Entre um valor numerico: ")
      N = tonumber(io.read())
      print()
 
      I = 1
      repeat
         R = N * I
         io.write(string.format("%2d", N))
         io.write(" X ")
         io.write(string.format("%2d", I))
         io.write(" = ")
         io.write(string.format("%3d", R), "\n")
         I = I + 1
      until not (I <= 10)
 
      print()
      print("Novo calculo?")
      io.write("[S] para Sim, outro valor para nao: ")
      RESP = io.read()
      print()
   until not (string.upper(RESP) == "S")
Ao ser executado o programa, seu comportamento é idêntico ao
cap0405.lua, tendo como diferencial a estrutura de laço estabelecida.

4.3 Laço iterativo


Nos tópicos anteriores, foram usados laços com os comandos while e
repeat.Esses laços permitem elaborar trechos de programas controlados
condicionalmente. No entanto, há na linguagem Lua uma terceira
maneira de se representarem laços. Trata-se do laço for que pode ser
usado de duas maneiras em Lua: forma tradicional, como encontrado em
outras linguagens de programação, ou forma genérica, particular da
linguagem Lua e que será tratado mais adiante.
Os laços de repetição que possuírem um número nito de execuções
(forma tradicional), caracterizando-se em laços iterativos, são controlados
por uma variável de controle do tipo contador (variável de controle),
podendo ser crescente ou decrescente, tendo como sintaxe para laço:
for <variável> = <inicio>, <fim>, <incremento> do
   instruções executadas dentro do laço
end
instruções executadas após conclusão do laço
Como exemplo de uso de laço iterativo, considere um programa
cap0408.lua que apresente como resultado a tabuada de um número
qualquer.
-- programa cap0408.lua
   io.write("Entre um valor numerico: ")
   N = tonumber(io.read())
   print()
 
   for I = 1, 10, 1 do
      R = N * I
      io.write(string.format("%2d", N))
      io.write(" X ")
      io.write(string.format("%2d", I))
      io.write(" = ")
      io.write(string.format("%3d", R), "\n")
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Os laços iterativos podem ser escritos num formato mais simpli cado. Por
exemplo, é possível omitir o terceiro argumento referente ao contado
quando o laço for possuir passo de um em um. Assim sendo, como
exemplo de uso, considere o programa cap0409.lua que apresente como
resultado a tabuada de um número qualquer.
-- programa cap0409.lua
   io.write("Entre um valor numerico: ")
   N = tonumber(io.read())
   print()
 
   for I = 1, 10 do
      R = N * I
      io.write(string.format("%2d", N))
      io.write(" X ")
      io.write(string.format("%2d", I))
      io.write(" = ")
      print(string.format("%3d", R))
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, o resultado apresentado será o mesmo
tanto para a ação da instrução for I = 1, 10, 1 do como para a instrução
for I = 1, 10 do, sendo o terceiro argumento do comando for opcional
para laços com passo de contagem “1”.
Outro detalhe a ser observado no código é o uso do comando print() na
apresentação de parte do resultado da tabuada em substituição à
instrução io.write(string.format("%3d", R), "\n").

4.4 Laço seletivo


Em um laço do tipo seletivo, é possível escolher o local em que o laço é
encerrado, além do topo e da base controlados pelos laços pré-teste e pós-
teste. Assim como os laços pré-teste e pós-teste, esse laço permite a criação
de ações iterativas e interativas.
Laços seletivos são encontrados, por exemplo, nas linguagens de
programação Ada, Rust e Structured BASIC. A linguagem Lua não possui
comando para a execução desse tipo de laço, mas isso não impede a
simulação dessa ação com o uso do comando goto em conjunto com o
comando if, sendo esta uma boa oportunidade de apresentar outro uso
propício ao comando goto em estilo bem comportado.
Dentro do escopo apresentado, o programa cap0410.lua, por meio da ação
do comando goto, apresenta a tabuada de um número qualquer
simulando a ação de um laço seletivo.
-- programa cap0410.lua
 
   io.write("Entre um valor numerico: ")
   N = tonumber(io.read())
   print()
 
   I = 1
   ::loop::
      R = N * I
      io.write(string.format("%2d", N))
      io.write(" X ")
      io.write(string.format("%2d", I))
      io.write(" = ")
      print(string.format("%3d", R))
      if (I > 9) then goto endloop end
      I = I + 1
      goto loop
   ::endloop::
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, seu resultado apresentado será idêntico aos
demais exemplos utilizados. O uso dos rótulos em inglês foi uma mera
formalidade para manter compatibilidade visual com as estruturas de
laços seletivos “do.. loop” encontrado na linguagem Structured BASIC,
loop... end loop encontrado na linguagem Ada e loop {... } encontrado
na linguagem Rust.
4.5 Interrupção na execução de laços
Os blocos de laços usados anteriormente mostram que sua execução é
realizada durante certo tempo. Num laço interativo, é executado enquanto
atende a certa condição, e, em um laço iterativo, é executado certo número
de vezes previamente de nido.
Um bloco de programa, de nido dentro de uma estrutura de laço, pode
ser interrompido quando certa condição ocorre, fazendo com que o laço
seja encerrado mesmo não atendendo sua condição ou sua iteração nal.
A interrupção de um laço é realizada com o comando break.
O comando break exige certo cuidado para que não ocorra erro em sua
aplicação, e deve ser de nido como último comando do bloco, pois a sua
execução impede que outros comandos sejam executados após ele, a
menos que seja essa a intenção do programador.
Por exemplo, o programa cap0411.lua efetua um laço de 1 até 10 e
apresenta o valor do contador até o laço ser interrompido antes de chegar
a 10, ou seja, apresenta apenas o primeiro valor da contagem. Esse
exemplo, se executado em versões anteriores à versão 5.3.4, poderá
apresentar uma mensagem de erro informando que não é possível
executar a ação, exigindo assim o uso de um bloco de comandos do...
end.
-- programa cap0411.lua
   I = 1
   while (I <= 10) do
      print(I)
      break
      I = I + 1
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Para versões mais antigas da linguagem Lua, considere como código
válido de execução o exemplo indicado para o programa cap0412.lua, que
poderá ser executado na versão 5.3.4 da linguagem Lua sem nenhum
problema.
-- programa cap0412.lua
   I = 1
   while (I <= 10) do
      print(I)
      do
         break
      end
      I = I + 1
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
O programa cap0413.lua efetua um laço de 1 até 10, mas, quando o
contador do laço for maior que 6, o programa será interrompido
apresentando a mensagem “Estourou". Nesse exemplo, observe que o
comando break está sendo de nido como último comando do bloco em
que se encontra de nido.
-- programa cap0413.lua
   I = 1
   while (I <= 10) do
      if (I <= 5) then
         print(string.format("%2d", I))
      else
         print("Vai estourar")
      end
      I = I + 1
      if (I > 6) then
         print("Estourou")
         break
      end
   end
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Na sequência, o programa cap0414.lua, semelhante ao programa
cap0413.lua com uso do comando break de nido antes da mensagem
“Estourou", caracteriza a não execução da linha de instrução que apresenta
a mensagem Estourou.
-- programa cap0414.lua
   I = 1
   while (I <= 10) do
      if (I <= 5) then
         print(string.format("%2d", I))
      else
         print("Vai estourar")
      end
      I = I + 1
      if (I > 6) then
         break
         print("Estourou")
      end
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.re ad '*l'
Ao ser executado o programa cap0414.lua em versões mais antigas da
linguagem Lua, um erro de execução poderá ser apresentado devido ao
fato de o comando break não ser o último comando do bloco.
A ação de interrupção de laço permite realizar com a linguagem Lua uma
segunda forma de simulação de laço seletivo com o uso dos comandos
while, if e break. Assim sendo, o programa cap0415.lua demonstra o uso
de laço seletivo simulado.
-- programa cap0415.lua
   io.write("Entre um valor numerico: ")
   N = tonumber(io.read())
   print()
 
   I = 1
   while (true) do
      R = N * I
      io.write(string.format("%2d", N))
      io.write(" X ")
      io.write(string.format("%2d", I))
      io.write(" = ")
      print(string.format("%3d", R))
      if (I > 9) then break end
      I = I + 1
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, será apresentada a tabuada do valor
numérico fornecido. Note que o programa utiliza a instrução while (true)
do, que faz com que o laço seja executado continuamente, se não fosse a
interrupção executada pela instrução if (I > 9) then break end.

4.6 Consistência de entrada de dados


Consistência de entrada de dados é uma técnica que serve para validar os
dados inseridos por um usuário em um programa. Alguns erros na
entrada podem fazer com que o programa seja abortado da memória ou
que ocorra um comportamento duvidoso.
A maneira de fazer essa veri cação é por meio de um laço repeat... until,
que permite uma entrada no laço para, em seguida, fazer a sua veri cação
condicional. Estando o dado inválido, força-se nova entrada; se o dado
estiver correto, dá-se continuidade ao programa.
Como exemplo, considere o seguinte programa, que efetua a entrada de
um valor numérico e apresenta-o somado a 5. Se o dado fornecido na
entrada for diferente de um valor inteiro ou real, o programa deve exibir a
mensagem de advertência “Erro - entre apenas valor numerico!". Grave o
programa com o nome cap0416.lua.
-- programa cap0416.lua
   repeat
      io.write("Entre um valor numerico: ")
      N = tonumber(io.read())
      if (type(N) == "number") then
         print("\nResultado = " .. N + 5)
         break
      else
         print("\nErro - entre apenas valor numerico!\n")
      end
   until not (true)
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao executar o programa, insira um dado que seja um caractere alfabético
e perceba que, nesse momento, aparece a mensagem que informa o erro
da entrada de dados. Se for informado um valor inteiro ou real, ele será
apresentado com mais 5.
Após a entrada, a linha com a instrução if (type(N) == "number") then
efetua uma veri cação condicional para determinar se a condição é
verdadeira. A função type() detecta o tipo do dado indicado, veri cando
se é um dado do tipo number. Se o dado informado for um valor numérico,
o resultado do valor informado mais 5 é informado e o comando break
efetua a saída do laço.
Uma vez capturado o erro, a mensagem “Erro - entre apenas valor
numerico!" é apresentada e nova tentativa de entrada deve ser executada
até que um valor válido seja informado.
Um detalhe a ser considerado é o uso da negação do valor true como
elemento condicional que determina a continuidade da execução do
comando repeat... until enquanto valores incorretos forem fornecidos.

4.7 Exercícios de xação


Desenvolver os programas elencados de 1 até 6 para os exercícios de A até
F, cando a cargo do professor selecionar a ordem e os problemas a serem
resolvidos.
A. Laço condicional pré-teste verdadeiro (while).
B. Laço condicional pré-teste falso (while com operador lógico “not”).
C. Laço condicional pós-teste falso (repeat).
D. Laço condicional pós-teste verdadeiro (repeat com operador lógico
“not”).
E. Laço condicional seletivo (simulado com os comandos goto e if antes
do contador).
F. Laço iterativo (for).
Assim, atente para os seguintes problemas:
1. Elaborar programa que apresente como resultado os quadrados
calculados a partir dos valores numéricos existentes na faixa de valores
de 15 a 200.
2. Elaborar programa que apresente a soma dos cem primeiros valores
numéricos de 1 até 100.
3. Elaborar programa que apresente o somatório dos valores pares na
faixa de 1 até 500.
4. Elaborar programa que apresente os valores numéricos ímpares
situados na faixa de 0 a 20.
5. Elaborar programa que apresente os valores numéricos divisíveis por
4 e menores que 200. A variável que controla o contador do laço deve
ser iniciada com valor 1.
6. Elaborar programa que leia dez valores numéricos e apresente no nal
o somatório e a média dos valores lidos.
CAPÍTULO 5

Programação com funções

Neste capítulo, são fornecidos detalhes sobre o uso de funções internas e


externas. O leitor terá contato com a criação de funções, passagens de
parâmetros e outros detalhes operacionais da linguagem como o uso de
funções anônimas, aninhadas, recursivas, biblioteca de funcionalidades e
tratamento de exceções.

5.1 Funções internas


A nalidade geral de uma sub-rotina de função é retornar um valor como
resposta à execução de sua ação. Na linguagem Lua, uma sub-rotina de
função pode retornar um ou mais valores e até não retornar nenhum
valor. Lua faz uso de funções internas e externas. Há funções em Lua que
podem possuir comportamento semelhante à ação de uma sub-rotina
procedimento, podendo retornar valores por seus parâmetros, além de
efetuar ações de entrada e saída dentro do corpo da sub-rotina.
As funções internas são o conjunto de recursos existentes nas bibliotecas
internas de uma linguagem. Lua possui como conjunto as bibliotecas:
básica; pacotes; manipulação de caracteres; manipulação de tabelas;
matemáticas; entrada e saída; acesso ao sistema operacional e depuração.
Anteriormente, fora utilizada a funcionalidade string.format(), que se
caracteriza por ser uma função da biblioteca de manipulação de
caracteres usada para a formatação de saídas de dados.
O programa seguinte apresenta alguns efeitos relacionados à sequência de
caracteres de nidos para a variável FRASE. O programa cap0501.lua
apresenta duas vezes o tamanho da frase string.len(), a frase em
caracteres minúsculos string.lower(), a frase em caracteres maiúsculos
string.upper() e a frase em caracteres invertidos string.reverse()).
-- programa cap0501.lua
   FRASE = "Linguagem Lua"
 
   print(string.len(FRASE))
   print(#FRASE)
   print(string.lower(FRASE))
   print(string.upper(FRASE))
   print(string.reverse(FRASE))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, a ação de cada instrução surte um efeito
diferente, exceto as instruções print(string.len(FRASE)) e print(#FRASE),
que apresentam o valor 13 como resposta ao tamanho em caracteres da
variável FRASE.
Outra biblioteca padrão muito requisitada é a biblioteca de funções
matemáticas em que se destacam funções para diversos cálculos. O
programa cap0502.lua apresenta alguns cálculos matemáticos obtidos a
partir de funções matemáticas, tais como: cosseno, seno, tangente, raiz
quadrada e valor inteiro do valor 1.12.
-- programa cap0502.lua
   VALOR = 1.12
 
   print(math.cos(VALOR))
   print(math.sin(VALOR))
   print(math.tan(VALOR))
   print(math.sqrt(VALOR))
   print(math.floor(VALOR))
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Nas operações de manipulação de strings, há ainda a possibilidade de
separar partes de uma sequência de caracteres. Para esse efeito, faz-se uso
da função string.sub(texto, início [,fim]), na qual texto é a indicação da
string que será separada, início é a indicação da posição de separação
inicial que pode ser positiva ou negativa e fim é uma indicação opcional
da posição nal de separação. O programa cap0502.lua demonstra
algumas ações de tratamento de sub strings.
-- programa cap0503.lua
   X = "COMPUTADOR"
 
   print(string.sub(X, 1))
   print(string.sub(X, 1, 3))
   print(string.sub(X, 4, 5))
   print(string.sub(X, 6, 7))
   print(string.sub(X, 8))
   print(string.sub(X, -5))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Após a execução, serão exibidos os textos COMPUTADOR, apresentado a partir
da posição 1 até o nal, COM, apresentado da posição 1 até a posição 3, PU,
apresentado da posição 4 até a posição 5, TA, apresentado da posição 6 até
a posição 7, DOR, apresentado a partir da posição 8 até o nal, e TADOR,
apresentado 5 posições do nal para a posição inicial.
Outro fator de manipulação de sequências de caracteres é a realização de
operações de substituição de caracteres em string. Para tanto, use a função
de substituição string.gsub(texto, busca, troca, vezes), em que texto é a
sequência de caracteres de nida, busca é o caractere a ser localizado, troca
é o caractere que será substituído e vezes indica o número máximo de
substituições a serem efetuadas, sendo esse último argumento opcional. O
programa cap0504.lua demonstra ações de substituição de caracteres em
string.
-- programa cap0504.lua
   X = "A BOLA AZUL APARECEU"
 
   print(string.gsub(X,"A","4"))
   print(string.gsub(X,"E","3",1))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Observe que, após a execução, o programa apresenta, além da troca
realizada, a quantidade de trocas efetuadas. A omissão do valor que
determina a quantidade de troca implica a troca de todos os caracteres
localizados. Quando de nida a quantidade, apenas o número
determinado será considerado na troca. Atente para as duas formas
apresentadas, veja que na primeira todos os caracteres A foram
substituídos por 4 e na segunda apenas um caractere E é substituído por 3.
Outra ação para manipulação de strings é a função string.rep(texto,
vezes), na qual texto é a parte a ser repetida e vezes é a de nição do
número de repetições. O programa cap0505.lua demonstra o uso da
repetição de caracteres em string.
-- programa cap0505.lua
   X = "OBA "
   print(string.rep(X,2))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Outro efeito com strings é a obtenção do código da tabela ASCII dos
caracteres que formam a sequência de caracteres com a funcionalidade
string.byte(texto, início [,fim]), em que texto é a indicação do texto
que terá seus caracteres convertidos em formato ASCII, início é a
indicação da posição de separação inicial que pode ser positiva ou
negativa, e fim constitui a indicação opcional da posição nal de
separação. O programa cap0506.lua apresenta os códigos ASCII de uma
sequência de caracteres na forma de string.
-- programa cap0506.lua
   X = "ABCDEF"
 
   print(string.byte(X, 1))
   print(string.byte(X, 1, 3))
   print(string.byte(X, 4, 5))
   print(string.byte(X, 1, 6))
   print(string.byte(X, -5))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
O programa apresenta os valores:
65
65 66 67
68 69
65 66 67 68 69 70
66
A ação inversa é obtida com a funcionalidade string.char(código1,
código2, …, códigoN), em que cada argumento usado é um valor ASCII. O
programa cap0507.lua apresenta os caracteres dos códigos ASCII
indicados.
-- programa cap0507.lua
   print(string.char(65))
   print(string.char(65, 66, 67))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Funções externas são funções de nidas pelo próprio programador em um
programa. Lua oferece alguns recursos operacionais muito atraentes no
uso de funções de nidas pelo programador. Toda função externa pode ser
utilizada com ou sem passagens de parâmetros e também usada como
instrução de comando da linguagem. A título de ilustração, observe a
função para limpeza do monitor de vídeo.
Uma forma de efetuar limpeza do monitor de vídeo é por meio da
execução do comando cls na janela de prompt de comando do Microsoft
Windows ou do comando clear na janela de terminal do comando do
Linux/UNIX (Mac OS X). Para fazer a execução do comando de limpeza
de tela cls ou clear, deve-se utilizar a função execute da biblioteca os com
a sintaxe os.execute("comando"), em que o comando será substituído pelo
comando de limpeza do monitor de vídeo do sistema operacional em uso:
os.execute("clear") no Linux ou os.execute("cls") no Microsoft
Windows. O programa cap0508.lua apresenta o recurso de limpeza de tela.
O programa cap0508.lua apresenta as mensagens e mantém indicada
apenas a segunda mensagem após a limpeza da tela.
-- programa cap0508.lua
   print("Primeira mensagem")
   os.execute("cls||clear")
   print("Segunda mensagem")
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, a primeira mensagem é apresentada e, em
seguida, ocorre a limpeza da tela e ca à mostra a segunda mensagem. O
uso dos comandos cls||clear permite que o código seja executado
igualmente tanto para o sistema operacional Windows como para os
sistemas operacionais padrão POSIX (Linux, Unix e Mac OS X).

5.2 Escopo e visibilidade de variáveis


Um ponto a ser considerado quando do uso de variáveis em Lua é o fato
de a de nição de uma variável sempre ser feita com escopo global. Caso
haja a necessidade de utilizar uma variável com escopo local, deve-se
antes do nome da variável usar a instrução local. O escopo local é
determinado pelo bloco no qual a variável é declarada. Uma variável com
escopo local que seja declarada fora de qualquer bloco é visível em todo o
programa. Por exemplo, o trecho de código seguinte é iniciado com a
variável X global com valor 33. Após a de nição condicional (X > 5), outra
variável X é de nida como local possuindo o valor 5. Dessa forma, há duas
variáveis com o nome X de nidas em memória: uma global com valor 33 e
outra local com valor 5. O programa cap0509.lua mostra os valores
de nidos para a variável X.
-- programa cap0509.lua
   X = 33
   print(X) -- mostra valor 33
   if (X > 5) then
      local X = 5
      print(X) -- mostra valor 5
   end
   print(X) -- mostra valor 33
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o trecho de código anterior será apresentado os valores
33, 5 e 33, sendo o valor 33 para a variável X com escopo global e o valor 5
para a variável X com escopo local.

5.3 Funções externas


O programa cap0510.lua apresenta o resultado do quadrado de um valor
lido via teclado. Para a execução do cálculo de quadrado, é apresentada a
função quadrado, que efetua cálculo quando chamada.
-- programa cap0510.lua
   function quadrado()
      QUAD = VLR * VLR
      return QUAD
   end
 
   VLR = tonumber(io.read())
   print(quadrado())
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Em relação ao programa cap0510.lua, este, após a entrada do valor na
variável VLR, faz a chamada da função quadrado() que, por sua vez, pega o
valor atribuído à variável VLR, calcula o quadrado e armazena seu
resultado na variável QUAD, o qual é pela instrução return QUAD devolvido
como resultado para a função quadrado().
Note que a de nição de uma função é feita com os comandos function e
end e que as variáveis VLR e QUAD como variáveis globais. Uma variável
global possui como escopo de visibilidade a capacidade de ser
“enxergada” por todo o programa, incluindo-se a parte principal e as
funções.
Quando uma variável é usada e de nida em um programa Lua, ela é por
padrão considerada com escopo global, a menos que seja explicitamente
de nida com escopo local por meio do comando local.
Por exemplo, ao olhar o código do programa cap0510.lua, nota-se que a
variável VLR é citada tanto na parte principal do programa como na
função. Dessa forma, essa variável deverá possuir escopo global, mas a
variável QUAD somente é usada no código da função. Assim sendo, essa
variável não precisa possuir escopo global, podendo ser de nida com
escopo local. Dessa forma, o programa cap0511.lua demonstra esta
ocorrência.
-- programa cap0511.lua
   function quadrado()
      local QUAD = VLR * VLR
      return QUAD
   end
 
   VLR = tonumber(io.read())
   print(quadrado())
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Note que no programa cap0511.lua ocorre o uso do comando local antes
da variável QUAD. Essa instrução fez com que QUAD seja uma variável local.
Dessa forma, ocorre um consumo menor de memória, pois, após a
conclusão da execução da função, a variável QUAD” é eliminada da
memória.

5.3.1 Passagem de parâmetro


Outra possibilidade de uso de funções em Lua é o uso de funções com
passagem de parâmetro. Considere, para tanto, o programa cap0512.lua,
que solicita a entrada de um valor numérico e apresenta como resultado a
fatorial do valor fornecido.
-- programa cap0512.lua
   function fatorial(N)
      local I, FAT
      FAT = 1
      for I = 1, N do
         FAT = FAT * I
      end
      return FAT
   end
 
   VLR = tonumber(io.read())
   print(fatorial(VLR))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
O programa cap0512.lua utiliza variáveis locais no código da função
fatorial(N), além do uso do parâmetro N que de ne o valor máximo de
execução do laço for. Outro detalhe no código da função é o uso do
limite do laço como I = 1, N, diferente de I = 1, N, 1. O uso do valor 1
após a de nição de N é opcional, sendo obrigatório apenas quando o
passo da contagem for maior que 1.
Um detalhe no uso de funções que deve ser considerado é em relação ao
uso de return para que o valor calculado seja retornado. Esse comando é
de certa forma opcional, pois, quando de sua ausência, a função não
retornará valor. Nesse caso, a função terá um comportamento semelhante
à de nição de procedimentos como existente na linguagem Pascal.
Normalmente funções sem retorno exigem o uso de variáveis com escopo
de visibilidade globais.
O programa cap0513.lua apresenta o resultado do cálculo da fatorial de
um número por meio de uma função que não retorna valor ao estilo
procedimento.
-- programa cap0513.lua
   function fatorial(N)
      local I, FAT
      FAT = 1
      for I = 1, N do
         FAT = FAT * I
      end
      io.write(FAT)
   end
 
   VLR = tonumber(io.read())
   print(fatorial(VLR))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Observe junto ao programa cap0513.lua que o resultado da operação é
impresso dentro do código da função.
A de nição de uma função assim como uma variável também poderá ter
seu escopo de nido como local. Para tanto, observe o uso do comando
local antes da de nição da função no programa cap0514.lua.
-- programa cap0514.lua
   local function fatorial(N)
      local I, FAT
      FAT = 1
      for I = 1, N do
         FAT = FAT * I
      end
      return FAT
   end
 
   VLR = tonumber(io.read())
   print(fatorial(VLR))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, o cálculo da fatorial é operacionalizado de
acordo com a ação da função fatorial() de nida como local.

5.3.2 Parâmetros arbitrários


Em alguns programas, foi utilizado o conceito de passagem de parâmetros
que também podem ser referenciados como argumentos. É importante
saber que a linguagem Lua não opera com passagem de parâmetro por
referência, apenas faz uso de passagem de parâmetro por valor. No
entanto, o código de uma função escrito em Lua pode retornar um
número arbitrário de parâmetros dando contrapartida como substituto à
necessidade de uso de passagem de parâmetro por referência. O programa
cap0515.lua mostra o uso de parâmetros arbitrários.
-- programa cap0515.lua
   function quantidade(N)
      if (N == 1) then
         return "UM"
      end
      if (N == 2) then
         return "UM", "DOIS"
      end
      if (N == 3) then
         return "UM", "DOIS", "TRES"
      end
   end
 
   VLR = tonumber(io.read())
   print(quantidade(VLR))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Observe que, ao ser executado o programa cap0515.lua, o retorno
dependerá do valor fornecido como parâmetro para a função
quantidade(VLR).
Outra forma de uso de arbitrariedade de parâmetros é quando os
parâmetros a serem usados são inde nidos. O programa cap0516.lua
seguinte usa parâmetro arbitrário por meio da de nição de três pontos (…)
que se caracteriza por ser a de nição de uma expressão do tipo vararg.
-- programa cap0516.lua
   local function fatorial(...)
      local I, FAT
      FAT = 1
      for I = 1, ... do
         FAT = FAT * I
      end
      return FAT
   end
 
   VLR = tonumber(io.read())
   print(fatorial(VLR))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Expressões do tipo vararg só podem ser utilizadas dentro de funções que
possuam número variável de argumentos. Esse tipo de operação não
ajusta sua lista de parâmetros; em vez disso, pega todos os parâmetros
extras, fornecendo-os para a função em uso por meio de uma expressão
vararg. O valor dessa expressão é uma lista de todos os argumentos extras
correntes, semelhante a uma função com retorno de múltiplos valores.

5.4 Funcionalidades especiais


A partir de uma visão básica mas fundamental do uso de sub-rotinas e
funções tanto internas quanto externas, é interessante conhecer algumas
outras funcionalidades que podem ser usadas com a linguagem Lua.

5.4.1 Função temporal


A linguagem Lua não possui de nida uma função que efetue uma pausa
controlada por tempo, mas por meio da função clock() da biblioteca io é
possível criar tal função. O programa cap0517.lua mostra o uso de uma
função de controle de tempo.
-- programa cap0517.lua
   function temporal(TMP)
      local TEMPO = os.clock()
      while (os.clock() - TEMPO <= TMP) do
      end
   end
 
   function pause()
      io.write("Tecle <Enter> para encerrar...")
      io.read '*l'
   end
 
   FAT = 1
   I = 1
 
   for I = 1, 5, 1 do
      FAT = FAT * I
   end
 
   for I = 1, 5 do
      temporal(4)
      print(FAT)
   end
   print()
   pause()
A função de nida temporal() recebe como valor de parâmetro o limite de
tempo de espera em segundos e marca o tempo inicial para a variável
TEMPO a partir do tempo atual. O ciclo while consome o tempo de execução
dentro do limite estabelecido para TMP enquanto o tempo atual
descontado do valor inicial de tempo em TEMPO seja menor ou igual ao
valor de nido para TMP.

5.4.2 Função aleatoriedade


Aleatoriedade é a característica do que é indeterminado ou incerto. Uma
das possibilidades operativas de uma linguagem de programação é a
capacidade de “gerar” valores numéricos aleatórios. O termo gerar é
grafado entre aspas devido à característica que os computadores possuem
de fazer esse trabalho de um modo considerado não real, ou seja, por
meio de uma ação considerada pseudoaleatória.
Para essa ação em linguagem Lua, há as funções de geração de números
aleatórios: math.randomseed() e math.rendom().
Os valores gerados por essas funções são valores pseudoaleatórios, e
devem ser usados com alguma cautela, tanto que há no manual de
referência da linguagem Lua a advertência: Nenhuma garantia pode ser
dada para suas propriedades estatísticas.
A função math.randomseed(N) usa o valor representado pelo parâmetro N
como parâmetro de semente para a geração de valores aleatórios.
A função math.random([N[,M]]) pode ser utilizada de três formas diferentes:
sem parâmetros, o que fará a geração de valores entre 0 e 1; apenas com o
parâmetro N, para gerar valores inteiros entre 1 e o valor estabelecido junto
a parâmetro N, e ainda com os parâmetros N e M para gerar valores inteiros
entre N e M.
O programa cap0518.lua efetua a ação de geração de valores aleatórios da
maneira mais simples possível.
-- programa cap0518.lua
   math.randomseed(0)
 
   local function sorteio()
      N = math.random()
      return N
   end
 
   for I = 1, 5 do
      X = sorteio()
      print(X)
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
A função math.randomseed() deve ser utilizada antes da função
math.random() para que math.random() consiga gerar os valores aleatórios.
Ao executar o programa várias vezes, os valores apresentados como saída
sempre serão:
0.23556518554688
0.64813232421875
0.074371337890625
0.27023315429688
0.36001586914062
Os valores se repetem pelo fato de ser utilizado o valor de semente 0
(zero). Se o valor de semente for mudado para 1, 2, 3 ou outro valor
qualquer, serão obtidos valores diferentes. No entanto, para um mesmo
valor de semente para mais de uma execução, ocorrerá a apresentação dos
mesmos valores. Uma forma de mudar um pouco esse comportamento é
usando a função os.time() como valor de semente. Essa função retorna o
valor do tempo corrente do computador em uso. Assim sendo, observe o
programa cap0519.lua seguinte:
-- programa cap0519.lua
   math.randomseed(os.time())
 
   local function sorteio()
      N = math.random()
      return N
   end
   for I = 1, 5 do
      X = sorteio()
      print(X)
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao se executar o programa algumas vezes, nota-se que os resultados
apresentados são levemente diferentes. Por exemplo, note a apresentação
dos valores de saída de duas execuções sequenciais do programa:
0.77081298828125 0.95523071289062
0.53692626953125 0.80169677734375
0.31997680664062 0.88189697265625
0.61093139648438 0.42465209960938
0.66482543945312 0.02020263671875
Observe que o uso da função os.time() como valor semente permite um
comportamento de aleatoriedade mais convincente.
A partir dos exemplos apresentados, ca fácil de nir um programa que
sorteie e apresente valores numéricos entre 1 e 5. Assim sendo, considere o
programa cap0520.lua seguinte:
-- programa cap0520.lua
   math.randomseed(os.time())
 
   local function sorteio()
      N = math.random(1, 5)
      return N
   end
 
   for I = 1, 5 do
      X = sorteio()
      print(X)
   end
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Execute o programa algumas vezes e observe os valores apresentados. Veja
que, para gerar valores entre 1 e 5, é usado: N = math.random(1,5).

5.4.3 Função recursividade


Não há como não falar de uso de funções sem considerar o efeito de
recursividade. Nesse sentido, a linguagem Lua também oferece tal recurso.
Recursividade é a capacidade que uma função possui de chamar a si
própria para efetivar certo cálculo.
O programa cap0521.lua demonstra o uso de função recursiva na
linguagem Lua.
-- programa cap0521.lua
   math.randomseed(os.time())
 
   local function fatorial(N)
      if (N <= 1) then
         return 1
      else
         return fatorial(N - 1) * N
      end
   end
 
   VLR = tonumber(io.read())
   print(fatorial(VLR))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Note junto ao programa cap0521.lua o uso da linha de instrução return na
qual se encontra fatorial(N - 1) * N, a chamada recursiva da função
fatorial().

5.4.4 Função anônima (Lambda)


Uma função anônima é uma sub-rotina sem nome, declarada e associada
diretamente a uma variável. Como exemplo desse tipo de ação considere o
programa cap0522.lua, que apresenta o somatório dos valores inteiros de 1
até um limite fornecido pelo usuário do programa.
-- programa cap0522.lua
   somatorio = function(N)
     local S = 0, I
     for I = 1, N do
       S = S + I
     end
     return S
   end
 
   io.write("Entre limite: ")
   VLR = tonumber(io.read())
 
   io.write("Soma = ")
   print(somatorio(VLR))
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, se fornecido o valor 100, será dado como
resposta o valor 5050, resultado do somatório de 1 a 100.
Funções anônimas aceitam recursividade. Tome por exemplo o cálculo da
fatorial de um valor qualquer indicado no programa cap0523.lua.
-- programa cap0523.lua
   fatorial = function(N)
     if (N <= 1) then
       return 1
     else
       return fatorial(N - 1) * N
     end
   end
   io.write("Entre limite: ")
   VLR = tonumber(io.read())
 
   io.write("Fatorial = ")
   print(fatorial(VLR))
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, se informado 5, será apresentado o
resultado 120.

5.4.5 Função enclausurada (Clousure)


Uma função do tipo de dado clousure (enclausurada) é aquela de nida
dentro de outra função, a qual possui acesso a variáveis de nidas fora do
escopo da função.
O programa cap0524.lua apresenta a sequência de Fibonacci a partir do
uso da função clousure.
-- programa cap0524.lua
   function fibonacci()
      local ATUAL = 1
      local ANTERIOR = 0
      local PROX
      return function()
         local PROX = ANTERIOR + ATUAL
         ANTERIOR = ATUAL
         ATUAL = PROX
         return PROX
      end
   end
 
   local X = fibonacci()
 
   for I = 1, 10 do
     print(X())
   end
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, são apresentados os valores 1, 2, 3, 5, 8, 13,
21, 34, 55 e 89.
A de nição da função enclausurada é realizada pela função anônima
de nida dentro da função fibonacci(). Assim sendo, observe a de nição
da função anônima function(), que efetua o cálculo da sequência de
Fibonacci dentro (enclausurada) da função fibonacci(), efetuando acesso
às variáveis locais ATUAL, ANTERIOR e PROX quando do uso da instrução
return function().

5.5 Biblioteca do programador (Módulo)


Na estrutura operacional de Lua, chama-se “módulo” a biblioteca de
funções e variáveis externa contidas em uma tabela de cunho global
utilizada por meio da função require(). Há a possibilidade de se trabalhar
com módulos a partir da função module(), mas esse não é o foco desta
obra.
A linguagem Lua possui alguns módulos em sua biblioteca padrão
(biblioteca interna), sendo:
• coroutine – Funções de uso do recurso de co-rotinas.
• debug – Funções para processo de depuração.
• io – Funções para as operações de entrada e saída.
• math – Funções para o uso de operações matemáticas.
• os – Funções que facilitam operações com o sistema operacional.
• package – Funções para o tratamento de módulos.
• string – Funções que manipulam sequências de caracteres.
• table – Funções para a manipulação de tabelas.
Os módulos da linguagem Lua: módulos do tipo padrão são
automaticamente carregados quando se usa o interpretador da linguagem,
não havendo necessidade de uso da função require(). O uso da função
require() é obrigatório quando da de nição e do uso de uma biblioteca
externa e particular criada pelo programador para atender às próprias
necessidades.
Para usar módulos de maneira simples, considere como exemplo o
seguinte código de programa a ser gravado com o nome modulo.lua:
-- programa MODULO
   function saudacao(NOME)
      print("Olá, " .. NOME)
   end
 
   function raiz(BASE,INDICE)
      local X = BASE ^ (1 / INDICE)
      return X
   end
Em seguida, escreva o código de programa cap0525.lua no mesmo local do
programa modulo.lua e execute-o.
-- programa cap0525.lua
   require("modulo")
 
   print("Seja bem vindo, visitante")
   io.write("Informe se nome: ")
   N = io.read()
 
   saudacao(N)
 
   io.write("Me de uma base .....: ")
   B = tonumber(io.read())
 
   io.write("Me de um indice ....: ")
   I = tonumber(io.read())
 
   R = raiz(B, I)
   io.write("Resultado = " .. R, "\n")
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Quando o programa cap0525.lua for executado, será aberto o acesso à
biblioteca modulo01 por meio da execução da linha de código
require("modulo").
A partir desse momento, cam disponíveis para o programa cap0525.lua as
funções da biblioteca externa modulo, as quais são executadas quando do
uso das linhas de instrução saudacao(N) e raiz(B, I).
As bibliotecas externas para uso na linguagem Lua poderão possuir as
extensões de identi cação .lua ou .so (ou .dll no caso do sistema
operacional da Microsoft).

5.6 Tratamento de exceções


Lua não possui instrução para tratamento de exceção do tipo try… throw…
catch, mas, por meio do auxílio das funções internas pcall() e error(), é
possível estabelecer um modo alternativo de realizar tal tarefa.
O programa cap0526.lua visa indicar mensagem de erro se um valor 0
(zero) for fornecido para o divisor de uma operação de divisão.
-- programa cap0526.lua
   local DIVID, DIV, QUOC
   local STATUS, ERRO
 
   io.write("Entre o dividendo ..: ")
   DIVID = tonumber(io.read())
 
   io.write("Entre o divisor ....: ")
   DIV = tonumber(io.read())
 
   STATUS, ERRO = pcall -- try
   (
     function()
        io.write("Resultado = ")
        if (DIV == 0) then
           error("Erro", 0) -- throw
        end
        QUOC = DIVID / DIV
        print(QUOC)
     end
   )
 
   if not (STATUS) then -- catch
      print(ERRO)
   end
Ao ser executado o programa, se informados os valores 5 e 2
respetivamente para o dividendo e divisor, será apresentada a mensagem
Resultado = 2.5; no entanto, se forem fornecidos os valores 5 e 0, será
apresentada a saída Resultado = Erro.
As variáveis DIVID, DIV e QUOC são de nidas para operar respectivamente
com os valores de dividendo, divisor e quociente.
As variáveis STATUS e ERRO são de nidas para operar com os valores lógicos
retornados pelas funções pcall() e error().
A função pcall() captura o erro ocorrido retornando um valor indicando
o status do erro. Essa função é usada para chamar uma função como
parâmetro, nesse caso, de nida como pcall (function() …). Se a chamada
ocorrer sem erro, pcall retorna verdadeiro e todos os resultados da
chamada. Se ocorrer erro, pcall retorna falso mais a mensagem de erro.
A função error() não retorna valor de erro, mas uma mensagem de
ocorrência que pode ser associada à informação sobre a posição onde o
erro ocorreu ou em que linha do programa a função está sendo utilizada.
Essa função pode utilizar dois parâmetros, sendo o primeiro obrigatório e
o segundo opcional. O segundo parâmetro, quando omitido, assume valor
1 (mostra a linha de código em que a função está de nida), se informado
o valor 0, nenhuma informação do local de ocorrência do erro é indicado,
mantendo-se apenas a mensagem de nida.
No código do programa, o equivalente a um bloco try é processado pela
função pcall. Se ocorrer um erro de divisão por zero, a função error() é
acionada simulando uma ação throw. O processamento de um bloco catch
é simulado pela instrução if not (STATUS).

5.7 Exercícios de xação


Desenvolver os programas elencados de 1 até 10, cando a cargo do
professor selecionar a ordem e os problemas a serem resolvidos. Utilize
sub-rotinas que simulem a estrutura operacional de um procedimento
com passagem de parâmetro por valor de modo que os resultados
calculados sejam apresentados dentro do escopo das sub-rotinas.
1. Elaborar programa de computador que calcule e apresente o resultado
do somatório dos N primeiros números, de nidos por uma pessoa de
modo que ocorra a operação de soma a partir da sequência
(1+2+3+4+5+6+7+...+N). Utilizar a entrada de valor natural.
2. Desenvolver algoritmo de programa de computador que calcule e
apresente o valor de uma potência de um número positivo (maior ou
igual a zero) qualquer elevado a um expoente positivo (maior ou igual
a zero) qualquer. Ao informar para a sub-rotina o número da base e do
expoente, deve ser apresentado o resultado da potência. Por exemplo,
se usado o procedimento potencia(2,3), deve-se apresentar o resultado
8. Resolva a exponenciação com uso de laço. Não use o operador de
exponenciação.
3. Elaborar programa que leia um valor numérico e apresente uma
mensagem informando se o número é par ou ímpar.
4. Elaborar programa que apresente como resultado um número
positivo, mesmo que a entrada tenha sido feita com valor negativo.
Desenvolver os programas elencados de 5 a 9 com base no uso de sub-
rotinas de funções que utilizem passagem de parâmetro por valor. Os
resultados das operações devem ser apresentados diretamente no trecho
principal do programa.
5. Elaborar programa de computador que calcule e apresente o
resultado do somatório dos N primeiros números, de nidos por uma
pessoa de modo que ocorra a operação de soma a partir da sequência
(1+2+3+4+5+6+7+...+N). Utilizar a entrada de valores positivos ou
negativos.
6. Desenvolver algoritmo de programa de computador que calcule e
apresente o valor de uma potência de um número positivo (maior ou
igual a zero) qualquer elevado a um expoente positivo (maior ou igual
a zero) qualquer. Ao informar para a sub-rotina o número da base e do
expoente, deve ser apresentado o resultado da potência. Por exemplo,
se usado o procedimento potencia(2,3), deve ser apresentado o
resultado 8. Resolva a exponenciação com uso de laço. Não use o
operador de exponenciação.
7. Elaborar programa que apresente como resultado um número
positivo, mesmo que a entrada tenha sido feita com valor negativo.
8. Elaborar programa que apresente o valor de uma temperatura em
graus Celsius. O programa deve ler a temperatura em graus
Fahrenheit.
9. Elaborar programa que apresente o valor de uma temperatura em
graus Fahrenheit. O programa deve ler a temperatura em graus
Celsius.
CAPÍTULO 6

Estruturas de dados

Este capítulo mostra como trabalhar com o agrupamento de dados em


uma mesma variável. Esse tipo de agrupamento permite que se utilizem
estruturas de vetores (listas) e estruturas de matrizes (tabelas). Quando
operada com dados de mesmo tipo, são estruturas homogêneas, e,
quando usada com tipos diferentes de dados, são estruturas heterogêneas
(registros).

6.1 Conjunto de dados


Os dados manipulados por computador são armazenados em variáveis.
As variáveis podem ser simples, quando armazenam um só dado, ou
compostas, quando armazenam mais de um dado em seu escopo de
operação. As variáveis compostas, dependendo de como são de nidas,
podem ser consideradas homogêneas, quando armazenam dados do
mesmo tipo, ou heterogêneas, quando armazenam dados de tipos
diferentes.
As variáveis compostas são referenciadas na literatura técnica da área da
computação com diversas nomenclaturas, como: vetores, tabelas,
matrizes, variáveis indexadas, conjuntos, listas, entre outras. Para este
texto está sendo considerado como forma genérica de conjuntos de dados
o termo “estrutura”.

6.1.1 Estrutura de vetores


Um vetor (tabela de uma dimensão) é representado por um nome de
identi cação e da de nição da dimensão de seu tamanho entre os
símbolos de chaves, tendo a seguinte sintaxe:
tabela = {}
O identi cador tabela deverá ser o nome da variável indexada a qual faz
uso dos símbolos de chaves “{ }” como construtores que criam e de nem
a estrutura de uma variável indexada na memória.
Para utilizar vetores na linguagem Lua, deve-se declarar o vetor no início
do código de programa antes de usá-lo. Não é necessário indicar a
quantidade de elementos (valores) que serão armazenados no vetor, pois a
própria linguagem efetua dinamicamente o ajuste da tabela à medida que
a tabela é utilizada.
A título de ilustração, considere o programa cap0601.lua que efetua a
leitura de dez elementos de um vetor denominado A. Em seguida,
construa um vetor denominado B, em que ele seja formado de acordo com
a seguinte lei de formação: se o valor do índice do vetor A for par, o valor
deve ser multiplicado por 5; sendo o índice do vetor B ímpar, deve ser
somado com 5. Mostrar os conteúdos dos vetores A e B. Este exemplo
mostra como fazer o tratamento da condição do índice.
-- programacap0601.lua
   A = {}
   B = {}
 
   io.write("Indice de Tabela")
   print()
 
   for I = 1, 10, 1 do
      io.write("Informe o ")
      io.write(string.format("%2d", I), "o. valor: ")
      A[I] = tonumber(io.read())
   end
 
   for I = 1, 10, 1 do
      R = I - 2 * (I // 2) -- ou R = I % 2
      if (R == 0) then
         B[I] = A[I] * 5
      else
         B[I] = A[I] + 5
      end
   end
   print()
   for I = 1, 10, 1 do
      io.write("A[", string.format("%2d", I), "] = ")
      io.write(string.format("%4d", A[I]), " - ")
      io.write("B[", string.format("%2d", I), "] = ")
      io.write(string.format("%4d", B[I]), "\n")
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
No programa, são usados três laços de repetição for: o primeiro laço
controla a entrada dos dados, o segundo veri ca se cada elemento da
matriz A é par ou ímpar processando o cálculo desejado, implicando os
elementos calculados na matriz B, e o terceiro é utilizado para apresentar
as duas matrizes.
No laço de processamento, é utilizada a instrução if (R == 0) then, sendo
a variável R carregada com o resultado da equação I - 2 * (I // 2) que
possibilita extrair o resultado do resto da divisão de inteiros do valor I
sobre o valor 2. Qualquer valor dividido por 2 que resultar zero é par; se o
resto for diferente de zero, o valor é ímpar.
Na sequência, será desenvolvido o programa cap0602.lua, que efetua a
leitura de cinco elementos de uma tabela A. No nal, apresente o total da
soma de todos os elementos que sejam ímpares. Em relação ao primeiro
exemplo, este apresenta uma diferença: o primeiro pedia para veri car se
o índice era par ou ímpar. Neste exemplo, é solicitado que seja feita uma
análise da condição do elemento, e não do índice em si. Já foi alertado
anteriormente para se tomar cuidado e não confundir elemento com
índice. Veja o programa.
-- programacap0602.lua
   A = {}
 
   io.write("Somatorio de elementos impares\n\n")
 
   for I = 1, 5, 1 do
      io.write("Informe o ")
      io.write(string.format("%2d", I), "o. valor: ")
      A[I] = tonumber(io.read())
   end
 
   SOMA = 0
   for I = 1, 5, 1 do
      R = A[I] % 2
      if (R ~= 0) then
         SOMA = SOMA + A[I]
      end
   end
 
   print()
   io.write("A soma dos elementos impares equivale a: ")
   io.write(string.format("%4d", SOMA), "\n")
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
No laço de processamento, é utilizada a instrução if (R ~= 0) then, para
veri car se o elemento informado pelo teclado é um valor ímpar; sendo,
ele é acumulado na variável SOMA que, ao nal, apresenta o somatório de
todos os elementos ímpares digitados durante a execução do programa.

6.1.2 Estrutura de tabelas


Com o conhecimento adquirido, é possível criar um programa que efetue
a leitura das notas escolares de oito alunos e apresente-as em seguida
utilizando apenas tabelas unidimensionais. Porém, há de se considerar
que esse tipo de trabalho é grande, uma vez que é necessário manter um
controle de cada índice em cada tabela para um mesmo aluno.
Para facilitar o trabalho com estruturas desse porte, utilize tabelas com
mais de uma dimensão. A forma mais comum a ser usada é a tabela de
duas dimensões. Tabelas com mais de duas dimensões são de uso menos
frequente, mas são fáceis de serem quando se conhece bem utilização de
tabelas com duas dimensões.
Um aspecto a ser considerado no uso de tabela unidimensional é o fato
de estar em uso apenas uma única instrução de laço de repetição. Em
relação às tabelas com mais dimensões, deve ser utilizado o número de
laços de repetição relativos ao tamanho de sua dimensão. Dessa forma,
uma tabela de duas dimensões deve ser controlada com dois laços de
repetição, uma de três dimensões deve ser controlada por três laços de
repetição e assim por diante.
Uma tabela de duas dimensões é aquela que possui um determinado
número de colunas com um determinado número de linhas. Por exemplo,
uma tabela com 5 linhas e 3 colunas é uma tabela de 5x3.
A de nição de matriz de duas dimensões na linguagem de programação
Lua deve ser feita seguindo a regra de de nição apresentada no programa
cap0603.lua:
-- programacap0603.lua
   A = {}
 
   io.write("Leitura e apresentacao de notas\n\n")
 
   for I = 1, 8, 1 do
      A[I] = {}
      print()
      io.write("Notas do ")
      io.write(string.format("%2d", I), "o. aluno: ")
      print()
      for J = 1, 4, 1 do
         io.write("Nota ", string.format("%2d", J), ": ")
         A[I][J] = tonumber(io.read())
      end
   end
 
   print()
   for I = 1, 8, 1 do
      print()
      io.write("Notas do aluno ")
      io.write(string.format("%2d", I), " sao: ")
      for J = 1, 4, 1 do
         io.write(string.format("%2d", J), ": ")
         io.write(string.format("%5.2f", A[I][J]), " ")
      end
   end
   print()
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, forneça as quatro notas de cada um dos
oito alunos e observe a apresentação dos dados como um pequeno
relatório.

6.1.3 Estrutura de enumeração


O uso de variáveis indexadas como listas de valores em linguagem Lua ao
estilo de listas enumeradas pode ser feito com a sintaxe:
DIA_SEMANA = {
  "domingo",
  "segunda-feira",
  "terca-feira",
  "quarta-feira",
  "quinta-feira",
  "sexta-feira",
  "sabado"
}
A variável DIA_SEMANA está formada com sete índices. Se for pedido o uso
da posição 1 como DIA_SEMANA[1], será pego o valor domingo, como pode ser
indicado no programa cap0604.lua seguinte:
-- programacap0604.lua
   DIA_SEMANA = {
      "domingo",
      "segunda-feira",
      "terca-feira",
      "quarta-feira",
      "quinta-feira",
      "sexta-feira",
      "sabado"
   }
 
   for I = 1, #DIA_SEMANA, 1 do
      print(DIA_SEMANA[I])
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
O uso de #DIA_SEMANA permite determinar a quantidade de elementos na
enumeração sem que seja necessário se preocupar efetivamente com esse
valor. Essa técnica se aplica a estruturas de dados.
Note que o primeiro índice da tabela é o índice 1, e não 0, como ocorre
em algumas outras linguagens de programação da família C. No entanto,
se for de vontade de nir o primeiro índice como zero, faça como indicado
no programa cap0605.lua:
-- programacap0605.lua
   DIA_SEMANA = {
      [0] = "domingo",
      "segunda-feira",
      "terca-feira",
      "quarta-feira",
      "quinta-feira",
      "sexta-feira",
      "sabado"
   }
 
   for I = 0, #DIA_SEMANA, 1 do
      print(DIA_SEMANA[I])
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Note que nessa versão o dia da semana domingo passa a estar posicionado
no índice zero da variável indexada, ou seja, posicionado em
DIA_SEMANA[0].
O trecho a seguir mostra a de nição explícita do índice de uma variável
indexada. Esse procedimento pode ser usado para todos os valores de
uma lista. Por exemplo:
ALIMENTO = {
   [1] = "cenoura",
   [2] = "batata",
   [3] = "beterraba",
   [4] = "arroz",
   [5] = "bacalhau"
}
Outra possibilidade de operação com listas em variáveis indexadas é a de
se usarem funções matemáticas como elemento da variável.
O programa cap0606.lua seguinte apresenta o resultado de algumas raízes
quadradas. Observe o uso da funcionalidade math.sqrt() como elemento
da variável indexada RAIZES.
-- programacap0606.lua
   RAIZES = {
      math.sqrt(16),
      math.sqrt(25),
      math.sqrt(36),
      math.sqrt(49)
   }
 
   for I = 1, #RAIZES do
      print(RAIZES[I])
   end
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Note a linha de código for I = 1, #RAIZES do e veja que nessa versão está
se omitindo o valor de incremento do contador. Quando isso é feito, a
linguagem Lua assume por padrão o passo de contagem em um.

6.1.4 Estrutura de registros


Uma variável indexada do tipo registro é normalmente uma estrutura de
dados que permite o uso de tipos de dados diferentes na mesma variável,
por meio da de nição de campos de dados.
A linguagem Lua não é rígida nesse sentido, pois trata automaticamente o
tipo do dado em uso. No entanto, é possível de nir dados em forma de
registros, de modo semelhante a outras linguagens.
O programa cap0607.lua faz a entrada e saída do nome e de quatro notas
escolares de um aluno. Observe atentamente o detalhe na de nição do
registro ALUNO com os campos NOME e NOTAS.
-- programacap0607.lua
   ALUNO = {
      NOME,
      NOTAS = {}
   }
 
   print("Cadastro de Aluno")
   print()
 
   io.write("Entre o nome .....: ")
   ALUNO.NOME = io.read()
   for I = 1, 4 do
      io.write(I .. "a. nota .: ")
      ALUNO.NOTAS[I] = tonumber(io.read())
   end
 
   print()
   print("Nome ...: " .. ALUNO.NOME)
   for I = 1, 4 do
      print("Nota " .. I .. " .: " .. ALUNO.NOTAS[I])
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Variáveis indexadas do tipo registro podem ser operacionalizadas pela
identi cação do nome do campo, como VARIÁVEL.CAMPO, bem como
VARIÁVEL["CAMPO"]. Note o programa cap0608.lua seguinte:
-- programacap0608.lua
   L = {C1 = 100, C2 = "Lua"}
   print(L["C1"]) -- escreve 100
   print(L["C2"]) -- escreve Lua
   print(L.C1) -- escreve 100
   print(L.C2) -- escreve Lua
   L.C1 = nil -- remove campo
   print(L.C1) -- escreve "nil"
   L.C1 = 500 -- insere campo
   print(L.C1) -- escreve 500
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Observe que o programa cap0608.lua faz uso de alguns elementos
operacionais sobre variáveis indexadas. Note que esse tipo de ação
possibilita o uso de diversos recursos para manipulação de varáveis
indexadas para operações com registros.
No que tange a utilização de variáveis indexadas de registros, Lua permite
outros graus de requinte, como demonstra o programa cap0609.lua:
-- programacap0609.lua
   L = {C1 = 2010, C2 = "Linguagem "}
   L[1] = "Lua"
 
   R = {math.sqrt(81), math.sqrt(49)}
   R.TXT = L
 
   print(R[2])
   print(R.TXT[1])
   print(L.C2 .. R.TXT[1])
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
O primeiro comando print apresenta o valor 7, resultado da raiz
quadrada de 49, o segundo comando print apresenta a palavra Lua, e o
terceiro comando print apresenta a frase concatenada Linguagem Lua.
Perceba que a de nição da variável R.TXT assume o valor da variável L[1].

6.2 Funções para estruturas


Anteriormente fora abordado o uso de tabelas unidimensionais, tabelas
bidimensionais e tabelas com listas de registros. Neste tópico serão
utilizadas algumas funções que possibilitam a realização de algumas
tarefas baseadas em tabelas, tais como funções de inserção e remoção de
elementos em tabelas: insert() e remove() existentes na biblioteca padrão
table da linguagem Lua.
O programa cap0610.lua efetua a ação de entrada e saída de elementos na
tabela VETOR.
-- programa cap0610.lua
   local VETOR = {}
 
   for I = 2, 10, 2 do
      table.insert(VETOR, I)
   end
 
   for I = 1, 5 do
      print("[" .. I .. "] = "..VETOR[I])
   end
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, note a apresentação da saída dele como:
[1] = 2
[2] = 4
[3] = 6
[4] = 8
[5] = 10
Perceba que foi de nida para a tabela VETOR a entrada dos valores pares de
2 até 10 de 2 em 2 por meio da função insert() da biblioteca table. A
função insert() fez uso de dois parâmetros, sendo o primeiro a de nição
do nome da tabela e o segundo o valor a ser inserido dentro da tabela. Na
sua operação, essa função pode trabalhar com até três parâmetros, sendo
o segundo parâmetro de uso opcional. Assim sendo, foram usados no
programa anterior, de fato, o primeiro e o terceiro parâmetros da função
insert().
Quando a função table.insert() está em uso, ela efetua a entrada do valor
na posição N + 1, em que N representa o tamanho da tabela. No entanto,
essa função permite escolher a posição de inserção de um elemento junto
à tabela, bastando utilizar um parâmetro a mais, indicado na segunda
posição.
O programa cap0611.lua efetua a entrada na tabela de quatro valores pares
e, em seguida, efetua a inserção do valor numérico ímpar 9 na primeira
posição da tabela.
-- programa cap0611.lua
   local VETOR = {}
 
   for I = 2, 10, 2 do
      table.insert(VETOR, I)
   end
 
   table.insert(VETOR, 1, 9)
 
   for I = 1, 6 do
      print("[" .. I .. "] = "..VETOR[I])
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Após a execução do programa, ocorre a apresentação da saída:
[1] = 9
[2] = 2
[3] = 4
[4] = 6
[5] = 8
[6] = 10
Observe que, após a inserção do valor 9 na primeira posição da tabela,
ocorreu o remanejamento de uma posição a mais para acomodar os
elementos existentes.
Para fazer a remoção de elementos de uma tabela, usa-se a função
table.remove().
O programa cap0612.lua efetua a remoção de elementos de uma tabela
de nida de maneira estática.
-- programa cap0612.lua
   local VETOR = {0, 2, 4, 6, 8}
 
   table.remove(VETOR)
 
   for I = 1, 4 do
      print("[" .. I .. "] = "..VETOR[I])
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Após a execução do programa, ocorre a apresentação da saída:
[1] = 0
[2] = 2
[3] = 4
[4] = 6
Note que a função remove() com a de nição do parâmetro VETOR efetuou a
remoção do último elemento da tabela. No entanto, essa função permite a
remoção de elementos a partir de uma posição de nida. Observe o
programa cap0613.lua seguinte:
-- programa cap0613.lua
   local VETOR = {0, 2, 4, 6, 8}
 
   table.remove(VETOR, 3)
 
   for I = 1, 4 do
      print("[" .. I .. "] = "..VETOR[I])
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Após a execução do programa, ocorre a apresentação da saída:
[1] = 0
[2] = 2
[3] = 6
[4] = 8
Perceba que o valor 4 que estava na terceira posição foi removido. Com a
remoção do valor 4, ocorreu o remanejamento dos outros valores.
No processo de manipulação de tabelas por funções há ainda a
possibilidade de usar a função sort() da biblioteca table para colocar os
elementos em ordem ascendente se forem strings ou crescente se forem
números.
O programa cap0614.lua demonstra o uso da função table.sort().
-- programa cap0614.lua
   local VETOR = {}
 
   for I = 1, 5 do
      NOME = io.read()
      table.insert(VETOR, NOME)
   end
   print()
 
   for I = 1, 5 do
      print("[" .. I .. "] = "..VETOR[I])
   end
 
   table.sort(VETOR)
   print()
 
   for I = 1, 5 do
      print("[" .. I .. "] = "..VETOR[I])
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Após a execução do programa, forneça a entrada de cinco nomes. Por
exemplo, se forem fornecidos os nomes: Joca, Augusto, Sílvio, Paula e
Sílvia, ocorre como saída:
[1] = Joca
[2] = Augusto
[3] = Silvio
[4] = Paula
[5] = Silvia
 
[1] = Augusto
[2] = Joca
[3] = Paula
[4] = Silvia
[5] = Silvio
Observe que na primeira parte da saída é feita a apresentação dos nomes
na ordem de em que foram entrados e, após a execução da função sort(),
os nomes são apresentados em ordem ascendente como indicado na
segunda parte da saída.
O programa cap0614.lua apresenta uma lista de valores em ordem
alfabética ascendente processada pela função sort() que permite operar a
ação de ordenação descendente com o estabelecimento de um pequeno
ajuste na função.
Observe o programa cap0615.lua que demonstra a ação de ordenação
alfabética descendente.
-- programa cap0615.lua
   local VETOR = {}
 
   for I = 1, 5 do
      NOME = io.read()
      table.insert(VETOR, NOME)
   end
   print()
 
   for I = 1, 5 do
      print("["..I.."] = "..VETOR[I])
   end
 
   table.sort(VETOR, function(A, B) return A > B end)
   print()
 
   for I = 1, 5 do
      print("["..I.."] = "..VETOR[I])
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Após entrar cinco nomes, serão mostrados os nomes na ordem de entrada
e ordenados de modo descendente.
Para conseguir ordenar os elementos do vetor em ordem decrescente, faz-
se uso no segundo parâmetro de sort() de um recurso baseado em uma
função em estilo lambda function(A, B) return A > B end que recebe dois
parâmetros e retorna o maior entre os dois valores fornecidos.

6.3 Estrutura metatabelas


Metatabela é um recurso que permite modi car o comportamento de
uma tabela a m de de nir qual ação pode ser tomada quando da
realização de uma operação sobre essa tabela. Cada tabela em uso pode
ter uma metatabela associada.
Para se de nir uma metatabela, é preciso utilizar a função setmetatable()
que faz uso de dois parâmetros, sendo o primeiro o nome da tabela e o
segundo o nome da metatabela. Assim sendo, observe a seguinte
de nição de metatabela:
local MT = {}
local TN = {}
setmetatable(TN, MT)
Em que MT é a metatabela e TN é a tabela normal. Isto posto, signi ca dizer
que MT é uma metatabela de TN.
O programa cap0616.lua tentará efetuar a soma de dois valores associados
cada um a uma tabela para criação de uma terceira tabela, mas não
conseguirá efetivar essa ação e, no momento do processamento da adição,
ocorrerá um erro que interromperá a execução do programa. Observe o
código seguinte:
-- programa cap0616.lua
   TABELA1 = {}
   TABELA2 = {}
   TABELA3 = {}
 
   TABELA1.a = 2
   TABELA1.b = 4
   TABELA1.c = 6
 
   TABELA2.a = 3
   TABELA2.b = 5
   TABELA2.c = 7
 
   TABELA3 = TABELA1 + TABELA2
 
   print(TABELA3.a)
   print(TABELA3.b)
   print(TABELA3.c)
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Note que assim que o programa for executado será apresentada a
mensagem de erro “attempt to perform arithmetic on a table value
(global 'TABELA1')".
O erro ocorre devido ao fato de as tabelas TABELA1 e TABELA2 não
possuírem metatabelas associadas. A linguagem Lua tenta efetuar a
adição de modo tradicional, o que leva a uma falha na execução do
programa. Para sanar o problema, é necessário de nir para as tabelas
normais uma operação de adição exclusiva para essas tabelas que serão
associadas as suas metatabelas.
A operação de soma será efetuada pelo uso do campo __add (antes de add,
usa-se duas vezes o símbolo under-line). Assim sendo, observe o
programa cap0617.lua:
-- programa cap0617.lua
   TABELA1 = {}
   TABELA2 = {}
   TABELA3 = {}
   METATAB = {}
 
   setmetatable(TABELA1, METATAB)
 
   METATAB.__add = function(V1, V2)
      TABAUX = {}
      setmetatable(TABAUX, getmetatable(V1))
      TABAUX.a = V1.a + V2.a
      TABAUX.b = V1.b + V2.b
      TABAUX.c = V1.c + V2.c
      return TABAUX
   end
 
   TABELA1.a = 2
   TABELA1.b = 4
   TABELA1.c = 6
 
   TABELA2.a = 3
   TABELA2.b = 5
   TABELA2.c = 7
 
   TABELA3 = TABELA1 + TABELA2
 
   print(TABELA3.a)
   print(TABELA3.b)
   print(TABELA3.c)
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao executar o programa, serão apresentados os resultados das adições dos
valores das tabelas TABELA1 e TABELA2, sendo 5, 9 e 13.
Além do uso do campo __add, é possível efetuar operações com os
campos:
• __sub (subtração)
• __mul (multiplicação)
• __div (divisão)
• __mod (resto de divisão de inteiros)
• __pow (exponenciação)
• __concat (concatenação)
• __len (tamanho)
• __eq (igualdade)
• __it (menor que)
• __le (menor igual), entre outras
No programa cap0617.lua, para execução da adição a linguagem Lua
veri ca a existência da metatabela e procura pelo campo __add que se
encontra de nido para a metatabela METATAB. Encontrando, executa ação
de adição desejada.

6.4 Estrutura interna


A de nição de uma estrutura interna pode ser estabelecida na linguagem
Lua a partir de vetores ou tabelas na forma de matrizes. Uma matriz é
considerada interna quando seus elementos são con gurados no próprio
código de um programa.
A de nição de uma estrutura interna na forma de vetor é declarada a
partir da indicação de elementos dentro das chaves. Por exemplo, para
de nir a variável composta A de uma dimensão com elementos pares, usa-
se:
local A = {0, 2, 4, 6, 8}
A de nição de uma estrutura interna na forma de tabela é declarada a
partir da indicação de elementos dentro de duas camadas de chaves. Por
exemplo, para de nir a variável composta A de duas dimensões com
elementos pares com três linhas e quatro colunas:
local A = {
             {11, 12, 13, 14},
             {21, 22, 23, 24},
             {31, 32, 33, 34}
          }
O programa cap0618.lua demonstra a apresentação dos valores subtraídos
e obtidos a partir de duas matrizes de duas dimensões.
-- programa cap0618.lua
   local A = {
                {11,22,33},
                {44,55,66},
                {77,88,99}
             }
 
   local B = {
                { 1, 2, 3},
                { 4, 5, 6},
                { 7, 8, 9}
             }
 
   local C = {}
 
   for I = 1, 3 do
      C[I] = {}
      for J = 1, 3 do
         C[I][J] = A[I][J] - B[I][J]
      end
   end
 
   for I = 1, 3 do
      for J = 1, 3 do
         print(C[I][J])
      end
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, é apresentada a saída 10, 20, 30, 40, 50, 60,
70, 80 e 90.
O programa faz uso das duas maneiras de de nição de matrizes de duas
dimensões em Lua. A primeira maneira é de nida de forma interna em
relação às variáveis indexadas A e B, e a segunda forma em relação à
variável indexada C é declarada inicialmente como local C = {} onde se
marca a primeira dimensão e dentro do ciclo de tratamento da variável I
como C[I] = {} para de nir-se a segunda dimensão da matriz.

6.5 Exercícios de xação


Desenvolver os programas dos problemas elencados de 1 até 13. Fica a
cargo do professor selecionar a ordem e os problemas a serem resolvidos.
1. Elaborar programa que efetue a leitura de 10 nomes de pessoas em
uma matriz NOME do tipo vetor e apresente-os em seguida.
2. Elaborar programa que leia 8 elementos numéricos em uma matriz A
do tipo vetor. Construir uma matriz B de mesma dimensão com os
elementos da matriz A multiplicados por 3. Apresentar os elementos da
matriz B.
3. Escrever programa que efetue a leitura de duas matrizes A e B do tipo
vetor com 5 elementos numéricos. Construir uma matriz C, sendo
cada elemento da matriz C a subtração de um elemento
correspondente da matriz A com um elemento correspondente da
matriz B. Ao nal, apresentar os elementos da matriz C.
4. Elaborar programa que efetue a leitura de 5 elementos numéricos de
uma matriz A do tipo vetor. Construir matriz B de mesmo tipo,
observando a seguinte lei de formação: “todo elemento da matriz B
deve ser o quadrado do elemento da matriz A correspondente”.
Apresentar os elementos das matrizes B.
5. Elaborar programa que leia duas matrizes do tipo vetor para o
armazenamento de nomes de pessoas, sendo a matriz A com 4
elementos e a matriz B com 3 elementos. Construir uma matriz C,
sendo esta a junção das matrizes A e B. Dessa forma, a matriz C deve ter
a capacidade de armazenar 7 elementos. Apresentar os elementos da
matriz C.
6. Elaborar programa que leia 6 elementos numéricos em uma matriz A
do tipo vetor e construir uma matriz B de mesma dimensão com os
mesmos elementos armazenados na matriz A, porém de forma
invertida. Ou seja, o primeiro elemento da matriz A passa a ser o
último da matriz B, o segundo elemento da matriz A passa a ser o
penúltimo da matriz B e assim por diante. Apresentar os elementos das
matrizes A e B.
7. Elaborar programa que leia duas matrizes A e B de uma dimensão com
6 elementos numéricos. A matriz A deve aceitar apenas a entrada de
valores pares, enquanto a matriz B deve aceitar apenas a entrada de
valores ímpares. A entrada das matrizes deve ser validada pelo
programa, e não pelo usuário. Construir uma matriz C que seja o
resultado da junção das matrizes A e B, de modo que a matriz C
contenha 12 elementos. Apresentar os elementos da matriz C.
8. Elaborar programa que leia uma matriz A de uma dimensão do tipo
vetor com 8 elementos numéricos. Ao nal, apresentar a quantidade de
elementos pares e ímpares da matriz.
Desenvolver os programas dos problemas elencados de 9 até 12. Fica a
cargo do professor selecionar a ordem e os problemas a serem resolvidos.
9. Elaborar um programa que leia duas matrizes A e B, cada uma de duas
dimensões com 5 linhas e 3 colunas para valores numéricos. Construir
uma matriz C de mesma dimensão, que seja formada pela soma dos
elementos da matriz A com os elementos da matriz B. Apresentar os
elementos da matriz C.
10. Elaborar programa que leia matriz A de duas dimensões com 3
linhas e 3 colunas para valores numéricos. Construir uma matriz B de
mesma dimensão, em que cada elemento da matriz B seja o dobro de
cada elemento correspondente da matriz A, com exceção dos
elementos situados na diagonal principal (posições B[1,1], B[2,2],
B[3,3], B[4,4] e B[5,5]), os quais devem ser o triplo de cada elemento
correspondente da matriz A. Apresentar ao nal a matriz B.
11. Elaborar programa que leia matriz A com valores numéricos para
duas dimensões com 4 linhas e 4 colunas. Apresentar o somatório dos
elementos situados na diagonal principal da referida matriz.
12. Elaborar programa que leia uma matriz A do tipo numérica com 5
linhas e 5 colunas. Construir uma matriz B de mesma dimensão, em
que cada elemento seja o dobro de cada elemento correspondente da
matriz A, com exceção dos valores situados na diagonal inversa
(posições B[1,5], B[2,4], B[3,3], B[4,2] e B[5,1]), os quais devem ser o
triplo de cada elemento correspondente da matriz A. Apresentar ao
nal a matriz B.
CAPÍTULO 7

Recursos complementares

Este capítulo apresenta parte de alguns recursos complementares para uso


da linguagem Lua. São indicados e demonstrados recursos, como:
passagem de parâmetro com matrizes, descrição de dados, orientação a
objetos, concorrência (co-rotinas), ações de arredondamento numérico e
outros ajustes como separação de valores de ponto utuante em expoente,
mantissa, teto e piso.

7.1 Descrição de dados


Uma das características da linguagem Lua desde seu desenvolvimento é a
capacidade de ser usada como linguagem de descrição de dados. Nesse
sentido, considere o código a seguir gravando-o com o nome popula.lua.
pessoa
{
   nome = "Augusto",
   profissao = "Professor",
   idade = 45
}
 
pessoa
{
   nome = "Antonio",
   profissao = "Medico",
   idade = 55
}
pessoa
{
   nome = "Mariana",
   profissao = "Engenheiro",
   idade = 30
}
 
pessoa
{
   nome = "Marcelo",
   profissao = "Medico",
   idade = 45
}
Na sequência será de nido um programa cap0701.lua que fará uso da
função pessoa() que realizará a apresentação dos nomes armazenados no
arquivo de dados popula.lua.
-- programa cap0701.lua
 
   function pessoa(DADOS)
      print(DADOS.nome)
   end
 
   dofile("popula.lua")
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Note que ao ser executado o programa os nomes existentes na descrição
de dados do arquivo popula.lua são apresentados.
Observe que a função pessoa() efetua o recebimento de um parâmetro
denominado DADOS que contém os registros de todos os dados do arquivo
popula.lua denominados pessoa e os insere na variável que se encontra
de nida como seu parâmetro, nesse caso, DADOS. O parâmetro DADOS está
sendo tratado como uma tabela. Os nomes dos registros existentes são
apresentados por meio da função print().
Note que a função em uso possui o mesmo nome de identi cação de
registro do arquivo popula.lua.
Para auxílio na obtenção dos dados do arquivo popula.lua, faz-se uso da
função dofile() que abre o arquivo indicado e executa o seu conteúdo
como se ele fosse um trecho de código escrito na linguagem Lua.
Outra possibilidade de uso do recurso de descrição de dados é a de nição
de uma tabela a partir dos dados existentes no arquivo popula.lua
possibilitando efetuar operações de controle dos dados. Observe o código
de programa cap0702.lua:
-- programa cap0702.lua
   local DADOS = {}
   local IND
   local VLR
 
   function pessoa(CONTEUDO)
      table.insert(DADOS, CONTEUDO)
   end
 
   dofile("popula.lua")
 
   for IND, VLR in pairs(DADOS) do
      if (VLR.idade >= 45) then
         print(VLR.nome)
      end
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa anterior, serão apresentados os nomes
Augusto, Antonio e Marcelo, que são os nomes dos registros cujas idades são
maiores ou iguais a 45 anos.
Para a execução do programa, perceba o trecho de código da função
pessoa() que por meio do parâmetro CONTEUDO faz a inserção deste dentro
da tabela DADOS.
Observe que as variáveis de uso do programa estão de nidas com escopo
de visibilidade local.
O programa faz uso de um laço for tipo genérico. Um laço genérico é
usado para percorrer os elementos de uma tabela, seus índices ou as
linhas de dados de um arquivo. Nesse caso, o laço genérico está
percorrendo os elementos da tabela DADOS por meio da função iteradora
pairs(), a qual pega na tabela um par de dados (índice e elemento). Caso
queira percorrer apenas os índices de uma tabela, usa-se a função
ipairs() e para as linhas de um arquivo usa-se a função io.lines().
A função pairs(), depois de percorrer os elementos de uma tabela,
retorna três valores, sendo o valor da posição do índice do próximo
elemento na tabela, o elemento da tabela e o valor nil quando ultrapassar
o m da tabela.
As variáveis IND e VLR do laço for genérico guardam respectivamente os
valores do índice e do conteúdo da tabela DADOS.

7.2 Princípio de orientação a objeto


A linguagem Lua não é propriamente orientada a objeto, mas isso não
impede que se faça uso desse paradigma de programação. Para operar
com classes, atributos, métodos e heranças, observe os seguintes detalhes.
Para utilizar o paradigma da orientação a objeto em Lua, é preciso criar
protótipos de classes a partir de metatabelas dos objetos dessa classe com
o uso do campo __index.
Primeiro, cria-se a estrutura básica de registro que será a base da classe.
Assim sendo, considerando-se a criação de uma classe chamada TALUNO
com os atributos NOME, NOTAS e MEDIA, faça:
TALUNO = {
   NOME,
   NOTAS = {},
   MEDIA
}
Observe que a de nição da estrutura de uma classe é realizada sobre a
mesma de nição que se faz para a de nição de um registro. A linguagem
Lua não é orientada a objeto, pois se fosse permitiria a de nição dentro
da estrutura TALUNO da indicação de chamada dos métodos de operação da
classe. Assim sendo, isso não pode ser usado em Lua, mas também não
impede o uso da orientação a objeto de certa forma.
Normalmente as linguagens de programação que operam com o
paradigma de orientação a objeto conseguem de nir uma variável a partir
da estrutura de uma classe. A essa ação se dá o nome de instância, e a
variável usada é chamada de objeto.
Algumas das linguagens de programação com orientação a objeto fazem a
instância de um objeto a partir do uso de um método interno chamado
new, como ocorre em Java TALUNO ALUNO = new TALUNO(). Será então
necessário criar na linguagem Lua um método semelhante.
Depois de de nir a estrutura da classe, passa-se para a etapa de
desenvolvimento do método que fará a criação do objeto em memória a
partir da classe TALUNO. Note o código do método new seguinte:
function TALUNO.new(OBJETO, ATRIB)
   ATRIB = ATRIB or {}
   setmetatable(ATRIB, OBJETO)
   OBJETO.__index = OBJETO
   return ATRIB
end
A função (método) ALUNO.new() faz uso de dois parâmetros, sendo o
primeiro a representação do objeto em si de nome OBJETO, e o segundo
representando os atributos da classe TALUNO. Essa função será usada para
instanciar um objeto.
A linha de instrução ATRIB = ATRIB or {} faz com que ocorra a criação de
um objeto vazio caso não seja passada nenhuma informação para esse
parâmetro.
A linha setmetatable(ATRIB, OBJETO) estabelece ATRIB como sendo
metatabela de OBJETO.
Na sequência, faz-se a atribuição OBJECT a OBJETO.__index de modo que, se
houver um acesso a um atributo ausente do objeto, a linguagem Lua fará
sua busca em ATRIB.
A linha return ATRIB devolve para o método ALUNO.new() o atributo do
objeto criado.
Depois de de nir a classe e estabelecer o método que fará a criação do
objeto, será de nida a instância do objeto. Observe o seguinte:
ALUNO = TALUNO.new(TALUNO)
A partir desse ponto, é possível escrever um programa orientado a objeto
em linguagem Lua.
Na sequência, será necessário preparar um método para o cálculo da
média do aluno. O resultado da média será atribuído ao atributo MEDIA do
objeto ALUNO. Dessa forma, estará sendo simulado o uso de métodos
externos. Para tanto, considere o código seguinte:
function ALUNO.CMEDIA()
   MEDIA = 0
   for I = 1, 4 do
      MEDIA = MEDIA + ALUNO.NOTAS[I]
   end
   RESULTADO = MEDIA / 4
   return RESULTADO
end
Considere o código de programa cap0703.lua com a manipulação de uma
classe, de atributos (campos membro) e de métodos.
-- programa cap0703.lua
   TALUNO = {
      NOME,
      NOTAS = {},
      MEDIA
   }
 
   function TALUNO.new(OBJETO, ATRIB)
      ATRIB = ATRIB or {}
      setmetatable(ATRIB, OBJETO)
      OBJETO.__index = OBJETO
      return ATRIB
   end
 
   ALUNO = TALUNO.new(TALUNO)
 
   function ALUNO.CMEDIA()
      MEDIA = 0
      for I = 1, 4 do
         MEDIA = MEDIA + ALUNO.NOTAS[I]
      end
      RESULTADO = MEDIA / 4
      return RESULTADO
   end
 
   io.write("Nome .....: ")
   ALUNO.NOME = io.read()
   for I = 1, 4 do
      io.write(I .. "a. nota .: ")
      NOTA = tonumber(io.read())
      ALUNO.NOTAS[I] = NOTA
   end
   ALUNO.MEDIA = ALUNO.CMEDIA()
 
   print()
   print("Nome ...: " .. ALUNO.NOME)
   for I = 1, 4 do
      NOTA = ALUNO.NOTAS[I]
      print("Nota " .. I .. " .: "..NOTA)
   end
   print()
   print("Media ..: " .. ALUNO.MEDIA)
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Depois de exempli car a de nição e o uso de classes, atributos e métodos,
é oportuno exempli car o uso de herança. Para demonstrar esse aspecto,
será de nida uma classe TSALA com atributo SALA que será herdado pela
classe TALUNO. Observe o trecho seguinte marcado em negrito:
TSALA = {
   SALA
}
 
TALUNO = { TSALA,
   NOME,
   NOTAS = {},
   MEDIA
}
Note que na classe TALUNO há a de nição de uso da classe TSALA. O uso de
TSALA como atributo de TALUNO é uma referência direta de herança sob a
classe TSALA e também ao seu atributo SALA. Dessa forma, está se
simulando em Lua a de nição de herança entre classe.
O programa cap0704.lua seguinte demonstra na linguagem Lua o uso de
herança.
-- programa cap0704.lua
   TSALA = {
      SALA
   }
 
   TALUNO = {TSALA,
      NOME,
      NOTAS = {},
      MEDIA
   }
 
   function TALUNO.new(OBJETO, ATRIB)
     ATRIB = ATRIB or {}
     setmetatable(ATRIB, OBJETO)
     OBJETO.__index = OBJETO
     return ATRIB
   end
 
   ALUNO = TALUNO.new(TALUNO)
 
   function ALUNO.CMEDIA()
      MEDIA = 0
      for I = 1, 4 do
         MEDIA = MEDIA + ALUNO.NOTAS[I]
      end
      RESULTADO = MEDIA / 4
      return RESULTADO
   end
 
   io.write("Nome .....: ")
   ALUNO.NOME = io.read()
   io.write("Sala .....: ")
   ALUNO.SALA = io.read()
   for I = 1, 4 do
      io.write(I .. "a. nota .: ")
      NOTA = tonumber(io.read())
      ALUNO.NOTAS[I] = NOTA
   end
   ALUNO.MEDIA = ALUNO.CMEDIA()
 
   print()
   print("Nome ...: " .. ALUNO.NOME)
   print("Sala ...: " .. ALUNO.SALA)
   for I = 1, 4 do
      NOTA = ALUNO.NOTAS[I]
      print("Nota " .. I .. " .: "..NOTA)
   end
   print()
   print("Media ..: " .. ALUNO.MEDIA)
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, perceba a integração de TSALA com TALUNO
como de nição de herança.

7.3 Princípio de concorrência


A concorrência é em essência um conjunto de programas ou mesmo de
sub-rotinas que podem ser executados em paralelo. Esse tipo de operação
computacional é usado na linguagem Lua por meio de “co-rotinas”
(concorrência).
Concorrência é uma atividade que permite suspender temporariamente a
execução de uma sub-rotina em determinado ponto de execução e ser
posteriormente executada em outro momento, ou seja, um uxo de
execução independente (IERUSALIMSCHY; FIGUEIREDO & CELES,
2011). Essa ação, conhecida como “ uxo de execução colaborativo
(collaborative multithreading)”, assemelha-se a um recurso em
programação chamado thread (IERUSALIMSCHY; FIGUEIREDO &
CELES, 2006).
A execução de co-rotinas em Lua ocorre por meio de uma linha de
execução independente que faz uso de uma pilha própria de chamadas.
Para usar esse recurso, Lua possui uma biblioteca (módulo) chamada
coroutine, a qual disponibiliza algumas funções operacionais, tais como:
coroutine.create()
coroutine.status()
coroutine.resume()
coroutine.wrap()
coroutine.yield()
O funcionamento de co-rotinas na linguagem Lua difere do modo
encontrado em sistemas convencionais multithreading, pois não efetua
ação que cause mudança de processamento. Em Lua, uma co-rotina só
pode ser interrompida quando termina ou quando para ela é chamada
explicitamente uma ação de suspensão de execução por intermédio da
função yield().
Para a criação de co-rotinas, podem-se usar as funções create() ou wrap().
A função create() cria uma nova co-rotina, mas não a coloca em
execução, deixando-a em modo de suspensão; para ser executada,
necessita da execução da função resume(). Já a função wrap() cria uma co-
rotina que possui como característica a capacidade de ser recomeçada
automaticamente toda vez em que a co-rotina é chamada.
A função yield(), como comentado, suspende a execução de uma co-
rotina de modo temporário.
A função status() detecta o estado operacional de uma co-rotina que
pode ser (JUNG & BROWN, 2007):
• suspended (modo de suspensão quando uma co-rotina tem seu uxo de
execução interrompido);
• running (modo de execução quando uma co-rotina está em operação);
• normal (quando uma co-rotina retorna seu uxo de execução a outra
co-rotina);
• dead (modo de encerramento quando uma co-rotina é normalmente
encerrada ou quando é retornado um erro de operação).
A função resume() é usada para iniciar a execução de uma co-rotina criada
por meio da função create(). Para efetuar um teste de uso de co-rotinas,
considere o programa cap0705.lua que apresenta a mensagem “Alo,
Mundo!", como segue.
-- programa cap0705.lua
   rotina = coroutine.create(
               function ()
                  print("Alo, Mundo!")
               end
            )
 
   print(coroutine.status(rotina))
   print(rotina)
   coroutine.resume(rotina)
   print(coroutine.status(rotina))
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, será apresentada a mensagem da primeira
linha de código que corresponde a suspended, pois, assim que a co-rotina
foi criada, esta ca em estado de suspensão na memória, tanto que ao ser
solicitada a ação print(rotina) é apresentada uma mensagem de erro
identi cada por “thread: 00000000007fb348", a qual poderá apresentar em
seu computador um valor numérico hexadecimal diferente. Essa é a prova
de que a co-rotina criada não pode ser executada.
Na sequência, ocorre a execução da linha de código com a chamada da
função resume() que faz a execução da co-rotina e apresenta a mensagem
Alo, Mundo!.
Na última linha, encontra-se novamente a execução da função status(),
que nesse momento indica a mensagem dead, informando que, após a
execução da co-rotina, esta foi removida da memória.
O programa cap0706.lua faz uso da função yield(). Observe o código
seguinte:
-- programa cap0706.lua
   rotina = coroutine.create(
               function ()
                  for I = 10, 16, 2 do
                     print(">> " .. I)
                     coroutine.yield()
                  end
               end
            )
 
   print(coroutine.status(rotina))
   print(rotina)
   coroutine.resume(rotina)
   print(coroutine.status(rotina))
   coroutine.resume(rotina)
   print(coroutine.status(rotina))
   coroutine.resume(rotina)
   print(coroutine.status(rotina))
   coroutine.resume(rotina)
   print(coroutine.status(rotina))
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, ocorrerá a apresentação da mensagem
“suspended" e também a apresentação da mensagem de erro. Em seguida, a
cada vez que é executada a função resume(), ocorre a chamada da co-
rotina e um valor da variável I do laço é apresentado, pois a cada vez que a
co-rotina é chamada a função yield() faz a interrupção dela.
O programa cap0707.lua faz uso de co-rotina criada com a função wrap().
Observe o código a seguir.
-- programa cap0707.lua
   rotina = coroutine.wrap(
              function (N)
                 R = N
                 print(R)
                 R = N * 2
                 print(R)
              end
            )
 
   N = 2
   rotina(N)
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado, o programa apresenta os valores 2 e 4. Note que nesse
exemplo a função wrap() possui sua funcionalidade semelhante à função
create().
Já no programa cap0708.lua, a co-rotina criada com a função wrap() é
interrompida com o uso da função yield().
-- programa cap0708.lua
   rotina = coroutine.wrap(
              function (N)
                 R = N
                 print(R)
                 coroutine.yield()
                 R = N * 2
                 print(R)
              end
            )
 
   N = 2
   rotina(N)
   rotina(N)
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Nesse exemplo, a co-rotina é chamada pela primeira vez e apresenta
apenas o valor 2, depois ocorre a segunda chamada que apresenta o valor
4. Observe que a função yield() faz uma interrupção na execução da co-
rotina retornando do ponto parado após sua chamada. Quando se faz uso
de co-rotina criada com a função wrap(), não há a necessidade de usar a
função resume() para dar continuidade na execução manual da co-rotina,
pois a função wrap() permite que esse avanço seja executado de maneira
automática.
O exemplo do programa cap0709.lua é uma adaptação de um programa
publicado no livro Beginning Lua Programming, páginas 278 e 279, dos autores
Kurt Jung e Aaron Brown, da editora Wiley Publishing, o qual mostra os
modos de apresentação do status no uso de co-rotinas.
-- programa cap0709.lua
   local A, B, C
 
   local function Status(Str)
      io.write(string.format(" %-11s | ", Str))
      io.write(string.format("A:%-9s | ",
         coroutine.status(A)))
      io.write(string.format("C:%-9s | ",
         coroutine.status(C)))
      io.write(string.format("Estado: [%9s]\n",
         tostring(coroutine.running()
         or "thread: inicial ")))
   end
 
   function A()
      Status("Rotina(A)")
   end
 
   function B()
      Status("Rotina(B)")
   end
 
   function C()
      Status("Rotina(C) 1")
      coroutine.resume(A)
      Status("Rotina(C) 2")
      B()
      Status("Rotina(C) 3")
      coroutine.yield()
      Status("Rotina(C) 4")
   end
 
   A = coroutine.create(A)
   B = coroutine.wrap(B)
   C = coroutine.create(C)
 
   Status("Principal 1")
   coroutine.resume(C)
   Status("Principal 2")
   coroutine.resume(C)
   Status("Principal 3")
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, apresentam-se os prognósticos de execução
das co-rotinas existentes.

7.4 Passagem de parâmetro por matriz


A linguagem Lua, como orientado, opera a ação de passagem de
parâmetro para uma sub-rotina de função somente por valor quando
aceita valores de nidos junto a variáveis simples. No caso de uma
passagem de parâmetro realizada por matriz, esta é, por padrão, por
referência.
O programa cap0710.lua demonstra o uso de passagem de parâmetro por
matriz. Assim sendo, o programa apresenta o resultado do somatório dos
elementos de uma matriz de nida internamente com valores de 1 até 5.
-- programa cap0710.lua
   function somatorio(VET, TAM)
      local S = 0
      local X
      for X = 1, TAM do
         S = S + VET[X]
      end
      return S
   end
 
   local A = {1, 2, 3, 4, 5}
 
   io.write("Soma = ")
   print(somatorio(A, 5))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa cap0710.lua, ocorre a apresentação da saída
Soma = 15. Nesse exemplo, não é possível perceber a ocorrência da ação de
referência em relação aos valores da matriz na passagem de parâmetro,
apenas notar que os valores da matriz foram transferidos para a função
somatorio().
O programa cap0711.lua demonstra a ação de passagem de parâmetro por
referência com matriz. O programa pega os valores de uma matriz interna
e apresenta seus valores elevados ao quadrado.
-- programa cap0711.lua
   function quadrado(VET, TAM)
      local X
      for X = 1, TAM do
         VET[X] = VET[X] ^ 2
      end
   end
 
   local A = {1, 2, 3, 4, 5}
   local FMT = string.format
 
   for I = 1, 5 do
      io.write("A["..I.."] = ")
      print(A[I])
   end
   print()
 
   quadrado(A, 5)
 
   for I = 1, 5 do
      io.write("A["..I.."] = ")
      print(FMT("%2d", A[I]))
   end
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, são apresentados os valores da matriz A
antes da execução da ação da função quadrado(), sendo então
apresentados os valores:
A[1] = 1
A[2] = 2
A[3] = 3
A[4] = 4
A[5] = 5
Na sequência, o programa executa a ação da chamada da sub-rotina
quadrado() e apresenta a saída dos valores:
A[1] = 1
A[2] = 4
A[3] = 9
A[4] = 16
A[5] = 25
Indicando a alteração dos valores de nidos na matriz A, a saída da matriz
é apresentada formatada a partir da instrução print(fmt("%6.2f", A[I])),
em que FMT é a de nição realizada com a instrução fmt = string.format
que associa string.format() à variável FMT permitindo usar a variável como
se fosse um comando da linguagem.

7.5 Conversão de tipos de dados


Uma das ações muito requisitadas em programação é a necessidade de se
fazer a conversão de um tipo de dado em outro tipo de dado. A linguagem
Lua opera de maneira dinâmica e muitas dessas ações se tornam por vezes
desnecessárias, mas há ocasiões em que é necessário efetivar de modo
coercitivo a conversão de dados. Parte do tema sobre conversão de dados
foi explanado no Capítulo 2.
A de nição de variáveis na linguagem Lua não exige que elas sejam
especi cadas como ocorre em outras linguagens. Devido a isso, é comum
programadores esquecerem que os tipos de dados existem e que estão
envolvidos com as variáveis em uso.
A veri cação dos tipos de dados de variáveis na linguagem Lua é feita
com o uso da função type(). Por exemplo, o programa cap0712.lua
apresenta exemplos e resultados de uso da função.
-- programa cap0712.lua
   A = 1
   B = 2.5
   C = "Alo, Mundo!"
   D = 'A'
   E = true
   F = string.format
 
   print("A = " .. type(A))
   print("B = " .. type(B))
   print("C = " .. type(C))
   print("D = " .. type(D))
   print("E = " .. type(E))
   print("F = " .. type(F))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa cap0712.lua, é indicado o tipo de cada uma
das variáveis especi cadas, como a seguir:
A = number
B = number
C = string
D = string
E = boolean
F = function
O programa cap0713.lua a seguir demonstra o uso da ação da função
type() veri cada em conjunto com o comando if:
-- programa cap0713.lua
   A = "10"
 
   if (type(A) == "number") then print("Numerico") goto fim end
   if (type(A) == "string") then print("Alfanumerico") goto fim end
   if (type(A) == "boolean") then print("Logico") goto fim end
   if (type(A) == "function") then print("Funcao") goto fim
   else
      print("Tipo de dado desconhecido")
   end
 
   ::fim::
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Outro recurso muito usado na conversão de dados é a função tonumber(),
que transforma o caractere alfanumérico informado como valor numérico
no seu correspondente number, muito usado em vários exemplos desta
obra. O programa cap0714.lua demonstra o efeito da ação da função
tonumber() na conversão de dados alfanuméricos em formato numérico.
-- programa cap0714.lua
   A = tonumber("10")
 
   if (type(A) == "number") then print("Numerico") goto fim end
   if (type(A) == "string") then print("Alfanumerico") goto fim end
   if (type(A) == "boolean") then print("Logico") goto fim end
   if (type(A) == "function") then print("Funcao") goto fim
   else
      print("Tipo de dado desconhecido")
   end
 
   ::fim::
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa cap0714.lua, é indicado que o valor 10 é do
tipo numérico. Note que o programa cap0713.lua mostra o resultado
alfanumérico para o mesmo valor antes do uso da função tonumber().
O programa cap0715.lua faz a conversão de um dado numérico na forma
alfanumérica por meio da função tostring().
-- programa cap0715.lua
   A = tostring(10)
 
   if (type(A) == "number") then print("Numerico") goto fim end
   if (type(A) == "string") then print("Alfanumerico") goto fim end
   if (type(A) == "boolean") then print("Logico") goto fim end
   if (type(A) == "function") then print("Funcao") goto fim
   else
      print("Tipo de dado desconhecido")
   end
 
   ::fim::
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa cap0715.lua, é indicado que o valor 10 é do
tipo alfanumérico.
Além da possibilidade de converter valores numéricos em valores
alfanuméricos e vice-versa, é possível efetuar conversões entre valores
inteiros e reais e vice-versa utilizando-se a função floor() da biblioteca
math e um truque de soma zero real com valor inteiro, como apresenta o
programa cap0716.lua.
-- programa cap0716.lua
   REAL = 3.14159
   INTEIRO = math.floor(REAL)
 
   print("Valor real como inteiro ..: " .. INTEIRO)
   print("Valor real como ..........: " .. REAL)
   print("Valor inteiro como real ..: " .. INTEIRO + 0.0)
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, são apresentados os valores 3, 3.14159 e 3.0.
A conversão de valor real em inteiro é executada pela função floor() da
biblioteca math, e de inteiro para real basta somar ao valor inteiro o valor
0.0.
Outra ação de conversão de dados que pode ser utilizada é a de valores
numéricos entre bases numéricas a partir da própria linguagem. O
programa cap0717.lua exempli ca algumas ações de conversão de bases
numéricas.

7.6 Arredondamentos e ajustes


A ação de arredondamento de valores tem por nalidade ajustar um valor
numérico de ponto utuante (valor real) estruturalmente ao se de nir a
quantidade de casas decimais que o valor deve internamente possuir na
mantissa.
É importante não confundir o arredondamento com a formatação "%f". O
código de formatação "%f" permite de nir a quantidade de casas decimais
que serão apresentadas na saída de um valor, mas não altera a
composição da mantissa do valor. Já a ação de arredondamento altera a
composição da mantissa de um valor numérico.
Considerando-se o valor numérico e ponto utuante 114.58889123
apresentado a partir do formato "%6.2f", será obtida na saída a
apresentação do valor 114.59. No entanto, internamente o valor continua
de nido na memória como 114.58889123.
Ao se de nir uma ação de arredondamento, o valor sofre alteração “física”,
ou seja, ele perde parte do valor após o arredondamento. Por exemplo, ao
se especi car round(114.58889123, 0.01), faz-se com que o valor seja
alterado para 114.59, sendo o excedente da mantissa perdido.
A linguagem Lua não possui em sua biblioteca matemática uma
funcionalidade para o tratamento de arredondamento de valores
numérico, cando a critério do programador criar essa funcionalidade.
Por ser Lua uma linguagem de programação mundialmente usada, há
uma comunidade de programadores que disponibilizam diversos recursos
como o site http://lua-users.org/wiki/.
Para utilizar a ação de arredondamento, considere a proposta
disponibilizada na página do site indicado http://lua-
users.org/wiki/SimpleRound implementada ao programa cap0717.lua
(adaptada e ajustada ao texto da obra).
A funcionalidade round() efetua os ajustes de arredondamento para um
valor de ponto utuante. O uso do nome da funcionalidade com a
identi cação math sugere a ideia de estar se considerando o uso de uma
funcionalidade matemática, seguindo como estrutura a biblioteca
matemática da linguagem.
Outros ajustes podem ser necessários no desenvolvimento de programas,
como separar as partes estruturais de um valor numérico de ponto
utuante como expoente e mantissa. Observe o código seguinte para o
programa cap0718.lua que apresenta o expoente, a mantissa, o piso e o
teto de um valor numérico.
-- programa cap0718.lua
   function math.exponent(VALOR)
      return math.floor(VALOR)
   end
 
   function math.mantissa(VALOR)
      return VALOR - math.floor(VALOR)
   end
 
   VALOR = 3.14159
   print("Exponete ...: " .. math.exponent(VALOR))
   print("Mantissa ...: " .. math.mantissa(VALOR))
   print()
   print("Teto .......: " .. math.ceil(VALOR))
   print("Piso .......: " .. math.floor(VALOR))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, as informações de teto ceil(), que faz o
arredondamento para o próximo inteiro do valor avaliado, e piso floor(),
que faz o arredondamento para o inteiro anterior ao valor avaliado, são
obtidas a partir da própria biblioteca math da linguagem. As
funcionalidades para obtenção do exponente() e da mantissa() são
de nidas manualmente por não fazerem parte dos recursos da linguagem.

7.7 Conversão de bases numéricas


Um ponto crucial no estudo das linguagens de programação é a
necessidade de se utilizarem bases numéricas diferentes da base decimal,
principalmente no que tange ao formato das bases binária, octal e
hexadecimal. Parte da conversão de valores em Lua é possível de ser
efetuada com recursos da própria linguagem como o uso das
funcionalidades tonumber() e string.format(). O que a linguagem não faz é
necessário ser de nido.
A funcionalidade tonumber() pode, além do que já foi exposto, realizar a
conversão de números inteiros de até 64 bits nas bases numéricas de 2 a
36 para o formato decimal. O programa cap0719.lua mostra a conversão
para decimal de alguns valores de nidos nas bases binária, octal e
hexadecimal.

Ao ser executado o programa cap0719.lua, é apresentada uma lista de


valores 10 sendo as formas de apresentação da conversão de seus
equivalentes em binário, hexadecimal e octal. Note que para a função
tonumber() é necessário primeiro informar o valor como string e segundo
de nir o valor de que base numérica o valor informado pertence para que
a conversão ocorra. O segundo parâmetro que determina o valor da base
opera com valores de 2 a 36. Quando um valor não possuir conversão,
ocorre a apresentação do valor nil.
A instrução print(tonumber(
"10111111001100011001011110001101111110110101101", 2)) apresenta, após
sua execução, o valor de 48 bits 105109858483629, podendo chegar até 64
bits, segundo a documentação da linguagem.
A ação inversa pode ser realizada com a função string.format() que
converte um valor numérico inteiro decimal em octal e hexadecimal. Não
é possível converter na forma binária, necessitando para tanto outro
procedimento operacional. O programa cap0720.lua demonstra a
conversão do valor inteiro 10 nas formas octal e hexadecimal.
-- programa cap0720.lua
   print(string.format("%x", 10))
   print(string.format("%X", 10))
   print(string.format("%o", 10))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, são apresentados o valor 10 convertido nas
formas hexadecimais minúsculo “a” e maiúsculo “A”, além da forma octal
como 12.
Quanto à conversão de um valor inteiro decimal na forma binária, é
necessário de nir uma função que realiza a operação. Assim sendo,
observe o código do programa cap0721.lua a seguir.
-- programa cap0721.lua
   function tobinary(VALOR)
      RESULTADO = ""
      while (VALOR ~= 0) do
         if (VALOR % 2 == 0) then
            RESULTADO = "0" .. RESULTADO
         else
            RESULTADO = "1" .. RESULTADO
         end
         VALOR = VALOR // 2
      end
     return RESULTADO
   end
 
   print(tobinary(10))
   print(tobinary(105109858483629))
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, são apresentados os valores 10 e
105109858483629 convertidos na sua forma binária.
A funcionalidade tobinary() faz a conversão de um valor decimal da
maneira mais tradicional possível, pegando cada valor do resto da divisão
sucessiva do valor por 2 e concatenando os restos para a composição do
valor binário.
CAPÍTULO 8

Arquivos em disco

Este capítulo apresenta detalhes introdutórios sobre operações com


manipulação de arquivos em disco operados na forma texto e binário. São
apresentadas informações básicas sobre criação, leitura, escrita e
fechamento de arquivos.

8.1 De nição de arquivos


Do ponto de vista computacional, um arquivo é visto como um conjunto
de registros, que, por sua vez, é um conjunto de campos, e cada campo
constitui o componente mínimo de um dado com a de nição de seu tipo,
sendo este um conjunto de bytes.
A principal vantagem no uso de arquivos é a capacidade de os dados
carem armazenados para uso a qualquer momento. Outra vantagem dos
arquivos é a capacidade de armazenarem um número maior de registros
do que em uma tabela em memória na forma de uma matriz, sendo
limitante dessa armazenagem apenas o tamanho do meio físico utilizado
para sua gravação.
A linguagem Lua possui uma biblioteca de entrada e de saída especí ca
para o controle de operações de arquivos.
Um arquivo é uma estrutura de armazenamento de dados que deve
efetuar duas ações operacionais: uma de abertura e outra de fechamento.
Quando um arquivo encontra-se aberto, pode ser usado para ler ou
escrever dados.
A de nição de arquivos com a linguagem Lua é executada a partir da
sintaxe:
VARIAVEL = io.open("nome","modo")
Para o fechamento de um arquivo aberto, usa-se a sintaxe:
VARIAVEL:close();
Em que VARIAVEL é a variável usada para controlar o acesso ao arquivo,
funcionalidade io.open() é a função que efetua a abertura de um arquivo
associando a VARIAVEL, e a funcionalidade close() é a função que efetua o
fechamento do arquivo.
Para ser usada, a função io.open() faz uso de dois parâmetros: nome que
determina o nome do arquivo e modo que de ne o modo de operação do
arquivo, como mostra a Tabela 8.1.
Tabela 8.1 – Operações de arquivos
Modo Descrição

r Modo leitura – forma padrão de acesso quando um arquivo é aberto

w Modo escrita – cria um novo arquivo ou substitui arquivo existente

a Modo adição – abre um arquivo existente ou cria um novo arquivo para adicionar

r+ Modo leitura e gravação de nido para um arquivo existente

w+ Modo escrita – cria novo arquivo apagando os dados existentes e coloca o novo
arquivo em modo de leitura e escrita

a+ Modo adição e leitura habilitados para quando um arquivo existe ou quando cria
um novo arquivo

b Modo de operação para manipulação de arquivos binários, usado ao lado direito


da de nição dos modos “r”, “w” e “a”

8.2 Tipos de arquivos


Os arquivos manipulados em um computador por meio da linguagem
Lua podem ser de nidos sob duas óticas: arquivos do tipo texto ou
arquivos do tipo binário. Por padrão, na linguagem Lua, os arquivos são
operacionalizados em modo texto. No sistema operacional Unix, não há
diferença entre arquivo binário e texto. Essa diferença ocorre em outros
sistemas operacionais, como Linux e Windows.
Os arquivos binários são tratados em Lua com o uso do modo de acesso
“B”, como será demonstrado mais adiante. Nesse formato de arquivo, a
Linguagem Lua opera o arquivo binário em relação ao arquivo texto com
uma pequena diferença operacional que será discutida com mais detalhe
no nal deste capítulo.
Os arquivos do tipo texto armazenam dados alfanuméricos no formato
ASCII puro. Esse tipo de arquivo armazena e manipula dados
con gurados, como letras, símbolos, palavras, frases e/ou números, que
podem ser acessados diretamente por programas de edição de textos,
como os programas bloco de notas, vi, emacs, nano, joe etc. O formato
usado para armazenar dados como arquivo texto é um modelo simples de
armazenamento, pois normalmente os dados são armazenados em linhas
de caracteres, nas quais o m do arquivo é determinado por um ou mais
caracteres de controle.
Os arquivos binários possuem uma con guração em que os dados são
armazenados na forma de uma sequência de bits (representado em sua
forma hexadecimal). Esse tipo de forma de armazenamento permite que
sejam guardados dados para as mais variadas aplicações, desde um
armazenamento simples de dados até dados que representem um arquivo
de imagem, por exemplo. Diferentemente dos arquivos textos, os arquivos
binários não podem ser editados por programas de edição de textos.
As operações de gerenciamento de arquivos na linguagem Lua são as
mesmas para uso de arquivos textos e binários.

8.2.1 Texto
Um arquivo texto consiste numa sequência de caracteres armazenados em
um “pacote” de dados gravado em uma mídia num formato conhecido
como ASCII. O conteúdo desse arquivo pode ser formado tanto por
sequências contíguas de caracteres, como por linhas identi cadas com o
uso de um caractere especial de controle chamado caractere de m de
linha. O arquivo texto também possui no seu nal gravado outro
caractere especial chamado caractere de m de arquivo.
O formato ASCII usado em um arquivo texto representa a gravação de um
dado com seu valor numérico referente à tabela ASCII, o qual representa
um dos 256 símbolos que um computador pode utilizar. Na prática
interna computacional, um arquivo texto é formado por uma sequência
numérica que é traduzida na forma textual quando se faz a leitura do
arquivo.
A escrita de dados num arquivo texto é efetuada no nal do arquivo e sua
leitura é executada sequencialmente a partir do início do arquivo. Esse
formato não é bom para o armazenamento de dados que necessitam de
atualizações constantes, como um arquivo para o cadastro de clientes de
uma empresa. Nesse caso, a melhor alternativa é o uso de arquivo binário
apresentado adiante.
Para ser usado pelo computador, um arquivo texto dá ao sistema
operacional um grau de trabalho maior do que um arquivo binário, pois
todos os dados fornecidos para gravação precisam ser traduzidos para o
formato ASCII a m de serem gravados no arquivo. No momento da
leitura, esses dados precisam ser convertidos para sua forma binária com
o intuito de que o sistema operacional possa direcioná-los para o uso
devido. Por exemplo, imagine gravar em um arquivo texto os caracteres
maiúsculos ABC, que serão armazenados com seus valores ASCII, sendo
065, 066 e 067 contiguamente, ou seja, 065066067. No momento da
leitura, o sistema operacional terá de pegar cada grupo de valores ASCII,
sendo 065, 066 e 067, e transformar cada grupo em seu respectivo valor
binário para este ser usado. Além disso, se é para ver esses valores no
monitor de vídeo, os valores serão lidos do arquivo, convertidos em
binário, levados ao bu er do monitor de vídeo e convertidos novamente
em formato ASCII para serem apresentados ao usuário do sistema, que,
normalmente, não conhece nada sobre esses detalhes.
Os exemplos deste tópico demonstram o uso básico de acesso e
manipulação de arquivos do tipo texto para a manipulação de caracteres
alfanuméricos com palavras ou frases. Para facilitar a identi cação desses
arquivos, será usada a extensão “TEX”, indicando arquivo do tipo texto.
Vale salientar que para a linguagem Lua o uso de extensão no nome do
arquivo é uma mera informação ilustrativa, podendo-se usar qualquer
nome para identi cação para uma extensão de arquivo.
O programa seguinte cria um arquivo do tipo texto de nome ARQTXT.TEX
com a utilização da função io.open(). Grave o programa com o nome
cap0801.lua.
-- programa cap0801.lua
   ARQTXT = io.open("arqtxt.tex","w")
   ARQTXT:close()
 
   print("Arquivo ARQTXT.TEX criado.")
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, o arquivo ARQTXT.TEX é criado e colocado
em modo de abertura. Na primeira linha do programa, ocorre a de nição
do arquivo no modo W para a variável ARQTXT por meio da função
io.open(). O uso do modo W efetua a criação do arquivo, mesmo que ele já
exista. Quando um arquivo é recriado em cima de si mesmo, os dados
anteriores são apagados. Além do modo W é possível usar o modo A que
cria um arquivo quando este não existe e sempre o abre para acrescentar
novos dados.
Na sequência, a instrução ARQTXT:close() fecha o arquivo criado.
Para veri car a criação do arquivo, solicite a apresentação do conteúdo do
local do disco onde o arquivo foi criado; nesse caso, o arquivo criado
estará com zero byte.
Após a criação do arquivo, ele pode ser utilizado para gravar dados com o
modo A. O programa seguinte efetua a leitura de palavras ou frase
efetuando a gravação do dado ao nal do arquivo ARQTXT.TEX. Grave o
programa com o nome cap0802.lua.
-- programa cap0802.lua
   ARQTXT = io.open("arqtxt.tex","a")
 
   io.write("Informe palavra ou frase: ")
   PALAVRA = io.read()
 
   ARQTXT:write(PALAVRA.."\n")
   ARQTXT:close()
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Depois de executar o programa e informar uma palavra ou frase, solicite
novamente a exibição do conteúdo do diretório de seu disco para ver o
arquivo ARQTXT.TEX com um número de bytes diferente de zero.
O programa cap0802.lua estabelece a abertura do arquivo em modo
acréscimo com a instrução ARQTXT = io.open("arqtxt.tex","a") que abre o
arquivo ARQTXT.TEX para a inclusão de uma nova palavra ou frase,
posicionando o ponteiro de controle de registros sempre no nal do
arquivo devido ao uso do código \n junto à instrução
ARQTXT:write(PALAVRA.."\n"). Caso o arquivo tenha alguma palavra ou
frase gravada, a próxima inserção será colocada após a última cadastrada,
efetuando o efeito de acréscimo de dados.
A seguir, o programa cap0803.lua efetua a leitura do arquivo texto
ARQTXT.TEX, apresentando no vídeo as palavras ou frases gravadas pelo
programa anterior.
-- programa cap0803.lua
   ARQTXT = io.open("arqtxt.tex","r")
 
   for PALAVRA in ARQTXT:lines() do
      io.write(PALAVRA.."\n")
   end
 
   ARQTXT:close()
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Para a extração do conteúdo de um arquivo, utiliza-se o modo de
operação R e se faz uso do laço for com a de nição de ação iteradora
(comando in) que percorrerá o arquivo com a função lines() e exibirá
cada uma das linhas lidas com a função io.write().
O programa cap0804.lua cria um arquivo em formato texto contendo
valores numéricos pares situados na faixa de valores entre 01 até 10.
-- programa cap0804.lua
   ARQTXT = io.open("pares.tex","w")
   FMT = string.format
 
   for I = 1, 10 do
      R = I % 2
      if (R == 0) then
         ARQTXT:write(FMT("%02d\n", I))
      end
   end
 
   ARQTXT:close()
 
   print("Arquivo com pares de 01 ate 10 criado.")
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
A linha de instrução R = I % 2 obtém o valor do resto da divisão do valor
da variável I por 2. Esse valor poderá ser 1 (se for ímpar) ou 0 (se for par).
A instrução if (R == 0) then veri ca se o valor do resto da divisão é zero,
sendo executada a instrução ARQTXT:write(FMT("%02d\n", I)) que escreve
no arquivo o valor par obtido. O indicativo "\n" junto ao código de
formatação está sendo usado para armazenar no arquivo um valor
numérico por linha. Sem esse recurso, os valores numéricos seriam
armazenados um ao lado do outro.
O programa cap0805.lua efetua não apenas a leitura do arquivo pares.tex,
mas também o somatório dos valores, além de mostrar seu resultado.
-- programa cap0805.lua
   ARQTXT = io.open("pares.tex","r")
 
   SOMA = 0
   for VALOR in ARQTXT:lines() do
      SOMA = SOMA + tonumber(VALOR)
   end
 
   ARQTXT:close()
 
   print("Soma dos pares: " .. SOMA)
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
O programa cap0805.lua faz uso da função tonumber(), que pega cada valor
numérico armazenado no arquivo na forma de string e o converte para
sua forma numeral. Apesar de a linguagem Lua realizar esse tipo de
conversão automaticamente, é recomendado que se de na esse tipo de
operação de modo explícito.
O programa cap0806.lua visa fazer a entrada de dados pessoais contendo
nome e telefone por meio do armazenamento de forma simples dos dados
em um arquivo texto chamado agenda.tex. O programa cria o arquivo (se
este não existir) colocando-o em modo de adição.
-- programa cap0806.lua
   ARQTXT = io.open("agenda.tex","a")
 
   RESP = "S"
   while (RESP == "S") do
 
      io.write("Nome .......: ")
      NOME = string.upper(io.read())
 
      io.write("Telefone ...: ")
      TELE = io.read();
 
      REGISTRO = NOME .. " " .. TELE
      ARQTXT:write(REGISTRO.."\n")
 
      io.write("[+]registro? S/N ")
      RESP = string.upper(io.read())
   end
 
   ARQTXT:close()
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
O programa usa a função io.open() com o modo de operação A para
permitir a inserção de novos registros ao arquivo. Atente também para o
uso da função string.upper() que transforma em maiúsculo as entradas
efetuadas junto às variáveis NOME e RESP.
O programa cap0807.lua efetua a leitura dos dados do arquivo agenda.tex.
-- fim cap0807.lua
   ARQTXT = io.open("agenda.tex","r")
 
   for REGISTRO in ARQTXT:lines() do
      io.write(REGISTRO.."\n")
   end
 
   ARQTXT:close()
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
É possível com a linguagem Lua criar um programa que efetue a criação
automática de páginas HTML/XHTML.
O programa cap0808.lua seguinte cria uma página em código XHTML.
-- programa cap0808.lua
   ARQTXT = io.open("teste.html","w")
 
   ARQTXT:write("<html><head><title>")
   ARQTXT:write("Livro de Linguagem Lua")
   ARQTXT:write("</title></head>")
   ARQTXT:write("<body>")
   ARQTXT:write("Linguagem Lua: Estudo Introdutorio")
   ARQTXT:write("</body></html>")
 
   ARQTXT:close()
 
   print("A pagina teste.html foi criada.")
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Observe junto ao programa as de nições das tags XHTML para criação
da página com o nome teste.html, a qual poderá ser executada por um
programa de navegação.
O programa cap0809.lua demonstra a abertura do arquivo agenda.tex para
leitura realizada pela função read() com parâmetro *all que fará a leitura
de todo o conteúdo atribuindo a leitura à variável DADOS. Após a leitura, é
criado o arquivo de escrita chamado agclon.tex com os dados clonados do
arquivo agenda.tex.
-- programa cap0809.lua
   ARQORG = io.open("agenda.tex","r")
   DADOS = ARQORG:read("*all")
   ARQORG:close()
 
   ARQCLO = io.open("agclon.tex", "w")
   ARQCLO:write(DADOS)
   ARQCLO:close()
 
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa cap0809.lua, ocorre a criação da clonagem
do arquivo agclon.tex. Observe que nesse programa se utiliza a função
read() com parâmetro *all que pode ser substituído pelo parâmetro *a e a
função write() que efetua a gravação de todos os dados associados à
variável DADOS.

8.2.2 Binário
Um arquivo binário consiste numa sequência de caracteres, que são
armazenados em um “pacote” de dados gravados em uma mídia num
formato numérico, formado por sequências binárias de valores
denominados byte na forma pura de sua representação. O arquivo binário
possui gravado no seu nal um caractere especial chamado caractere de
m de arquivo.
O programa cap0810.lua cria um arquivo em formato binário contendo
valores numéricos pares situados na faixa de valores entre 01 até 10.
-- programa cap0810.lua
   ARQBIN = io.open("pares.bin","wb")
   FMT = string.format
 
   for I = 1, 10 do
      R = I % 2
      if (R == 0) then
         ARQBIN:write(FMT("%02d\n", I))
      end
   end
 
   ARQBIN:close()
 
   print("Arquivo com pares de 1 ate 10 criado.")
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
O programa cap0810.lua é similar ao programa cap0804.lua, apresentando
como diferencial o fato de operar o arquivo em formato binário. O
programa cap0811.lua realiza a leitura e a apresentação do arquivo
pares.bin.
-- programa cap0811.lua
   ARQBIN = io.open("pares.bin","rb")
 
   for REGISTRO in ARQBIN:lines() do
      io.write(REGISTRO.."\n")
   end
 
   ARQBIN:close()
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Os programas de gerenciamento de arquivos binários possui a mesma
forma de sintaxe dos arquivos textos. A diferença está na de nição dos
modos de operação para criação do arquivo como “WB”, podendo-se usar
os modos “AB” e “RB” dependendo da ação que se deseja realizar.
A seguir, são apresentados dois exemplos de programas com uso de
arquivos binários com dados do tipo numérico por meio de matriz A de
uma dimensão com oito elementos.
O programa a seguir solicita a entrada de dez valores numéricos
armazenando esses valores em uma matriz a m de transferi-los de uma
só vez para o arquivo ARQBIN.BIN. Grave o programa com o nome
cap0812.lua.
-- programa cap0812.lua
   ARQBIN = io.open("arqbin.bin","wb")
   FMT = string.format
   A = {}
 
   for I = 1, 8 do
      io.write("Informe o ")
      io.write(FMT("%2d", I), "o. valor: ")
      A[I] = tonumber(io.read())
   end
 
   for I = 1, 8 do
      ARQBIN:write(A[I] .. "\n")
   end
 
   ARQBIN:close()
 
   print("Arquivo gravado.")
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, informe os valores e, em seguida, veri que
a de nição do arquivo.
O programa cap0813.lua efetua a leitura dos dados armazenados no
arquivo arqbin.bin transferindo a leitura de cada valor para uma posição
da matriz A.
-- programa cap0813.lua
   ARQBIN = io.open("arqbin.bin","rb")
   A = {}
 
   I = 1
   for REGISTRO in ARQBIN:lines() do
      A[I] = REGISTRO
      print(A[I])
      I = I + 1
   end
 
   ARQBIN:close()
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, os dados armazenados do arquivo são
apresentados. Note que, pelo fato de se estar em uso uma ação iteradora
com o comando for... in... do, torna-se necessária a de nição da
variável REGISTRO inicializada e incrementada para controlar os índices de
acesso da matriz A.

8.3 Controle de operações


As operações de acesso a arquivos podem na linguagem Lua ser
veri cadas quanto ao sucesso da operação, pois a tentativa de abertura de
um arquivo inexistente pode ocasionar erro de acesso nas operações de
leitura e escrita ocasionando a interrupção da execução do programa.
O programa seguinte tenta abrir para leitura o arquivo inexistente
denominado DADOS.PPP com o modo de operação “RB”. Essa ação não
ocasiona, no programa exemplo, uma interrupção da execução do
programa por não estar sendo realizada nenhuma operação de escrita ou
leitura. Grave o programa com o nome cap0814.lua.
-- programa cap0814.lua
   ARQUIVO = io.open("dados.ppp","rb")
 
   if (ARQUIVO == nil) then
      print("Arquivo inexistente")
      io.open("dados.ppp","wb")
   else
      print("Arquivo encontrado")
   end
   
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao ser executado o programa, o arquivo dados.ppp não é encontrado e a
mensagem “Arquivo inexistente" é apresentada; neste mesmo momento, a
instrução io.open("dados.ppp","wb") cria o arquivo que na segunda
execução do programa é identi cado como existente e a mensagem
“Arquivo encontrado" é apresentada. A variável ARQUIVO, ao ser atribuída
pela ação de abertura, armazena o valor nil caso o arquivo não exista, daí
o uso da condição ARQUIVO == nil para validar a abertura ou criação do
arquivo.

8.4 Arquivo de acesso direto


O acesso direto, também denominado acesso randômico, permite mover o
ponteiro de arquivo para qualquer posição do arquivo em uso. Nos
exemplos de arquivos apresentados, não se levou em conta a forma de
acesso aos dados (todos os exemplos foram criados com base no acesso
sequencial). Para o exemplo a ser construído neste tópico, será utilizada a
forma de acesso direto, pois esse tipo de arquivo permite o acesso
imediato a cada um dos seus registros, desde que se conheça previamente
a posição em que os dados estão gravados.
Para se ter acesso às posições de dados dentro de um arquivo, a linguagem
Lua possui a função seek() que, relacionada a um arquivo, pode ser
utilizada a partir das possibilidades:
• ARQUIVO.seek() para retornar a posição em que se está no arquivo;
• ARQUIVO:seek ("set", 0) para posicionar o ponteiro no início do
arquivo;
• ARQUIVO:seek ("end") para posicionar o ponteiro no nal do arquivo;
• ARQUIVO:seek ("end", -10) para posicionar o ponteiro 10 bytes antes do
nal do arquivo;
• ARQUIVO:seek ("cur", 5) para posicionar o ponteiro 5 bytes a partir da
posição atual;
O programa cap0815.lua efetua a leitura de valores numéricos inteiros
positivos no formato de máscara 9999 que estejam entre 1 e 9.999,
gravando-os na posição nal do arquivo MATINT.BIN por meio do modo
“AB”, ou seja, a gravação é realizada sequencialmente sempre no nal do
arquivo.
- programa cap0815.lua
   ARQUIVO = io.open("matint.bin","ab")
 
   FORMATO = #"9999" + 1
   POSICAO = (ARQUIVO:seek("end") // FORMATO) + 1
 
   print("Cadastro sequencial de valores")
   print()
   repeat
      print("Entre o " .. POSICAO .. "o. registro.\n");
      repeat
         io.write("Entre um valor numerico: ")
         VALOR = tonumber(io.read())
      until (VALOR >= 1) and (VALOR <= 9999)
      ARQUIVO:write(string.format("%4d\n", VALOR))
      print("\nDeseja continuar?")
      io.write("[S] para Sim \n[qualquer letra] para Nao\n\n--> ")
      RESP = io.read()
   until (string.upper(RESP) ~= "S")
 
   ARQUIVO:close()
 
   print()
   io.write("Tecle <Enter> para encerrar...")
   io.read '*l'
Ao executar o programa, insira alguns valores inteiros e, ao sair do
programa, execute-o novamente, inserindo mais valores. Perceba que o
programa indica a próxima posição ordinal do novo cadastro. Anote os
valores indicados para que sejam veri cados posteriormente com o
próximo programa.
O programa cap0815.lua lança mão de alguns recursos operacionais como
a de nição das variáveis FORMATO e TAMANHO. A variável FORMATO é atribuída
com o valor do tamanho do bloco de caracteres usado para gravar os
dados, formado pela quantidade de caracteres mais uma posição do
código de nova linha. A variável TAMANHO calcula a quantidade de registros
contida no arquivo, a qual é obtida a partir do tamanho do arquivo
ARQUIVO:seek("end") dividido com quociente inteiro a partir do formato
de nido para o registro.
A entrada do programa aceita apenas o fornecimento de valores
numéricos entre 1 e 9.999, o qual, após validação gravada no arquivo de
acordo com o formato "%4d\n", além de estabelecer as quatro posições
de ne o código de mudança de linha que forma a base do cálculo da
variável FORMATO. As posições à esquerda do formato não usadas são
de nidas com espaços em branco.
O programa cap0816.lua lê um valor armazenado utilizando o acesso
direto (aleatório ou randômico), pois solicita uma posição especí ca do
arquivo e apresenta, em seguida, o conteúdo capturado na tela.
Ao ser executado o programa, é possível efetuar as consultas dos dados
armazenados no arquivo. O programa cap0816.lua possui muitos detalhes
usados no programa cap0815.lua. No entanto, há detalhes que merecem
atenção, como a instrução ARQUIVO:seek("set", 0) que coloca o ponteiro
do arquivo sempre na primeira posição dentro do laço. Após o
fornecimento da posição de pesquisa no arquivo, a instrução
ARQUIVO:seek("set", (POSICAO - 1) * FORMATO) efetua o posicionamento no
registro desejado para proceder a sua leitura com a instrução VALOR =
ARQUIVO:read("*line"), em que o parâmetro *line é usado para acessar a
linha do registro.
Após a leitura, é realizada a apresentação do registro pesquisado com a
instrução io.write("\nValor: " .. VALOR:gsub("^%s*", "")), em que a
função gsub() é usada para remover do dado pesquisado todos os espaços
em branco que estão a sua esquerda.
O programa cap0817.lua solicita uma posição do arquivo e pede um novo
valor que é gravado na posição indicada. Dessa forma, é possível alterar
valores em certa posição do arquivo. Para essa ação, é usado o modo de
operação do arquivo como “R+B” que fará tanto a ação de leitura como
escrita de certo registro.
Ao ser executado o programa cap0817.lua, forneça uma posição do
arquivo e informe um novo valor. O valor informado é sobreposto ao
valor anterior que poderá ser veri cado junto ao programa cap0816.lua.

8.5 Considerações sobre arquivos binários e texto


Como comentado no Tópico 8.2, o tratamento de arquivos em Lua é por
padrão modo texto. Para usar o modo binário, utiliza-se o modo de
operação “B”, no entanto o arquivo ainda mantém uma estrutura
semelhante ao modo texto. Dessa forma, arquivos texto ou binário criados
em Lua podem ser abertos e lidos em qualquer programa de edição de
texto, como o bloco de notas, vi, emacs etc.
Para um teste operacional sobre essa ação, execute os programas
cap0804.lua para criar ou recriar o arquivo texto com os valores pares entre
01 até 10 denominado PARES.TXT e, em seguida, abra o arquivo em um
editor de texto simples, como o programa “Bloco de notas” no Windows
indicado na Figura 8.1, e note os valores apresentados no sentido vertical.

Figura 8.1 – Arquivo “PARES.TEX” no “Bloco de notas”.


Uma das características de um arquivo texto gravado em Lua é fazer a
gravação após cada entrada de dado dos símbolos de retorno do cursor
(caractere: “cret” com código hexadecimal 0Dh ou 13d) e de mudança de
linha (caractere: “newl” com código 0Ah ou 10d) que não são
apresentados quando o arquivo é visualizado a menos que se utilize um
editor hexadecimal como o programa “Hex Editor Neo”, como mostra a
Figura 8.2 destacando um trecho da tela.

Figura 8.2 – Arquivo “PARES.TEX” no “Hex Edir Neo”.


Observe, junto à Figura 8.2, a indicação dos valores “0d” e “0a”
demonstrando o registro do acionamento da tecla <Enter> que faz a
mudança de linha (newl) e retorno de cursor (cret). Os demais valores
representam o código ASCII hexadecimal dos símbolos numéricos
utilizados.
O formato binário na linguagem Lua especi ca um arquivo contendo
apenas como separador de dados o caractere de mudança de linha (newl)
e os dados gravados na forma ASCII. Assim, o arquivo binário não
contém o código de mudança de linha.
Para um teste, execute o programa cap0810.lua para criar ou recriar o
arquivo binário com os valores pares entre “01” até “10” denominado
PARES.BIN e, em seguida, abra o arquivo em um editor de texto simples,
como o programa “Bloco de notas” no Windows indicado na Figura 8.3 e
note que a sequência de dados no editor de texto é indicada no sentido
horizontal.

Figura 8.3 – Arquivo “PARES.BIN” no “Bloco de notas”.


Pelo fato de o arquivo em formato binário não gravar o caractere (cret), o
conjunto de dados ocupa menos espaço, como pode ser constatado junto
à Figura 8.4 que apresenta o trecho de tela do programa “Hex Editor Neo”.

Figura 8.4 – Arquivo “PARES.BIN” no “Hex Edir Neo”.


Veja na Figura 8.4 a indicação apenas do código “0a” entre os dados
cadastrados no arquivo, sendo essa a forma como a linguagem Lua trata
seus arquivos.

8.6 Exercícios de xação


Desenvolver os programas dos problemas elencados de 1 até 10. Fica a
cargo do professor selecionar a ordem e os problemas a serem resolvidos.
1. Ler por meio do teclado 10 valores numéricos inteiros entre 0 e 999
em uma matriz A de uma dimensão. Após a leitura, os dados devem
ser armazenados no formato 999 em arquivo binário denominado
dados.dbn. Usar para a criação do arquivo o modo de operação “WB”.
2. Elaborar programa que leia os valores numéricos armazenados no
arquivo dados.dbn. Em seguida, ler o arquivo e transferir por ação
iterativa os valores para a memória junto à matriz B. Apresentar os
elementos da matriz B de uma dimensão utilizando a função seek()
para determinar a quantidade de dados a serem lidos. O programa
deve reconhecer automaticamente a quantidade de elementos no
arquivo.
3. Elaborar programa que leia 5 valores numéricos no formato 999 que
estejam entre 1 e 999 e acrescente-os aos elementos existentes no
arquivo dados.dbn (não use o modo de operação “WB”).
4. Elaborar programa que efetue a leitura dos dados do arquivo
dados.dbn acrescentando em uma matriz B do tipo vetor os valores
existentes no arquivo. Em seguida, o programa deve indicar a
quantidade de elementos pares, ímpares e o percentual de pares e
ímpares em relação ao total de valores armazenados.
5. Elaborar programa que efetue a leitura dos dados do arquivo
dados.dbn apresentando os valores armazenados que sejam divisíveis
por 2 e 3 e suas respectivas posições.
6. Elaborar programa que efetue a leitura dos dados do arquivo
dados.dbn apresentando as posições ocupadas e seus respectivos
conteúdos.
7. Elaborar programa que apresente na tela o registro do valor na
posição 10.
8. Elaborar programa que efetue a cópia dos dados do arquivo principal
dados.dbn para o arquivo reserva dados.res.
9. Elaborar programa que efetue a leitura dos dados do arquivo
dados.dbn gravando os dados pares no arquivo pares.dbn.
10. Elaborar programa que efetue a leitura dos dados dos arquivos
dados.dbn e pares.dbn e apresente os registros existentes nos arquivos.
Referências bibliográ cas

EMMERICH, P. Beginning Lua with World of Warcraft Addons. USA: Apress, 2009.
GUTSCHMIDT, T. Game Programming with Python, Lua, and Ruby. USA: Premier
Press, 2003.
IERUSALIMSCHY, R.; FIGUEIREDO, L. H. de; CELES W. Lua 5.2 Reference
Manual. Rio de Janeiro: Lua.org, 2011.
_____________. Programming in Lua. 2. ed. Rio de Janeiro: Lua.org, 2006.
INFO EXAME. O mundo se rende à brasileira Lua. Desenvolvimento, 2009.
Disponível em: <http://info.abril.com.br/professional/desenvolvimento/o-mundo-se-
rende-a-brasileira-lua.shtml>.
JUNG, K.; BROWN, A. Beginning Lua Programming (Programmer to Programmer).
USA: Wrox; 2007.
UNIVERSIA. Lua conquista Microsoft. Notícia, 2002. Disponível em:
<http://noticias.universia.com.br/destaque/noticia/2002/08/30/540541/lua-conquista-
microsoft.html>.
Introdução à linguagem Python
Manzano, José Augusto N. G.
9788575227152
352 páginas

Compre agora e leia

Este livro apresenta a linguagem Python 3 de forma básica e


introdutória para leitores e estudantes de programação que não
possuem conhecimentos prévios da linguagem. Neste texto
encontra-se a apresentação de detalhes e informações sobre:
características básicas da linguagem, tipos de dados built-in;
variáveis; constantes internas; operadores aritméticos; expressões
aritméticas; operações de entrada e saída; condições; decisões;
operadores relacionais e lógicos; desvios condicionais; ações de
divisibilidade; expressões condicionais; laços; sub-rotinas como
funções e procedimentos; passagem de parâmetro; funções lambda;
programação com módulos; tratamento de dados; estruturas de
dados; orientação a objetos; manipulação de arquivos externos;
constantes para localização geográfica; conversões entre bases
numéricas; simulação para definição de constantes; uso do modo
terminal ANSI; plataforma cruzada e aplicação com geometria de
tartaruga (turtle graphics).

Compre agora e leia


Como ser um programador melhor
Goodliffe, Pete
9788575227640
384 páginas

Compre agora e leia

Se você é apaixonado por programação e quer se aperfeiçoar nisso,


está com a fonte de informações perfeita. Pete Goodliffe, autor de
Code Craft, apresenta um conjunto de técnicas e abordagens úteis
para a arte da programação que irá ajudá-lo a impulsionar a sua
carreira e a melhorar o seu bem-estar. Goodliffe apresenta
conselhos sólidos, aprendidos em 15 anos de programação
profissional. Os capítulos independentes do livro cobrem o espectro
da vida de um desenvolvedor de software – lidar com código,
conhecer os negócios e melhorar o desempenho – sem ideias
tendenciosas sobre qualquer linguagem ou mercado.
Independentemente de ser um desenvolvedor experiente, um
profissional novato ou um programador por hobby, você encontrará
dicas valiosas em cinco categorias independentes: ■■ Técnicas no
nível de codificação para compor linhas de código, testar, depurar e
lidar com a complexidade. ■■ Práticas, abordagens e atitudes:
manter a simplicidade, trabalhar bem em equipe, reutilizar e criar
códigos maleáveis. ■■ Táticas para aprender de maneira eficiente,
comportar-se de modo ético, encontrar desafios e evitar a
estagnação. ■■ Maneiras práticas de completar tarefas: usar as
ferramentas certas, saber qual é a aparência de "pronto" e procurar
ajuda dos colegas. ■■ Hábitos para trabalhar bem com outras
pessoas e encarar o desenvolvimento como uma atividade social.

Compre agora e leia


Padrões para Kubernetes
Ibryam, Bilgin
9788575228159
272 páginas

Compre agora e leia

O modo como os desenvolvedores projetam, desenvolvem e


executam software mudou significativamente com a evolução dos
microsserviços e dos contêineres. Essas arquiteturas modernas
oferecem novas primitivas distribuídas que exigem um conjunto
diferente de práticas, distinto daquele com o qual muitos
desenvolvedores, líderes técnicos e arquitetos estão acostumados.
Este guia apresenta padrões comuns e reutilizáveis, além de
princípios para o design e a implementação de aplicações nativas
de nuvem no Kubernetes. Cada padrão inclui uma descrição do
problema e uma solução específica no Kubernetes. Todos os
padrões acompanham e são demonstrados por exemplos concretos
de código. Este livro é ideal para desenvolvedores e arquitetos que
já tenham familiaridade com os conceitos básicos do Kubernetes, e
que queiram aprender a solucionar desafios comuns no ambiente
nativo de nuvem, usando padrões de projeto de uso comprovado.
Você conhecerá as seguintes classes de padrões: • Padrões
básicos, que incluem princípios e práticas essenciais para
desenvolver aplicações nativas de nuvem com base em contêineres.
• Padrões comportamentais, que exploram conceitos mais
específicos para administrar contêineres e interações com a
plataforma. • Padrões estruturais, que ajudam você a organizar
contêineres em um Pod para tratar casos de uso específicos. •
Padrões de configuração, que oferecem insights sobre como tratar
as configurações das aplicações no Kubernetes. • Padrões
avançados, que incluem assuntos mais complexos, como
operadores e escalabilidade automática (autoscaling).

Compre agora e leia


Candlestick
Debastiani, Carlos Alberto
9788575225943
200 páginas

Compre agora e leia

A análise dos gráficos de Candlestick é uma técnica amplamente


utilizada pelos operadores de bolsas de valores no mundo inteiro.
De origem japonesa, este refinado método avalia o comportamento
do mercado, sendo muito eficaz na previsão de mudanças em
tendências, o que permite desvendar fatores psicológicos por trás
dos gráficos, incrementando a lucratividade dos investimentos.
Candlestick – Um método para ampliar lucros na Bolsa de Valores é
uma obra bem estruturada e totalmente ilustrada. A preocupação do
autor em utilizar uma linguagem clara e acessível a torna leve e de
fácil assimilação, mesmo para leigos. Cada padrão de análise
abordado possui um modelo com sua figura clássica, facilitando a
identificação. Depois das características, das peculiaridades e dos
fatores psicológicos do padrão, é apresentado o gráfico de um caso
real aplicado a uma ação negociada na Bovespa. Este livro possui,
ainda, um índice resumido dos padrões para pesquisa rápida na
utilização cotidiana.

Compre agora e leia


Avaliando Empresas, Investindo em
Ações
Debastiani, Carlos Alberto
9788575225974
224 páginas

Compre agora e leia

Avaliando Empresas, Investindo em Ações é um livro destinado a


investidores que desejam conhecer, em detalhes, os métodos de
análise que integram a linha de trabalho da escola fundamentalista,
trazendo ao leitor, em linguagem clara e acessível, o conhecimento
profundo dos elementos necessários a uma análise criteriosa da
saúde financeira das empresas, envolvendo indicadores de balanço
e de mercado, análise de liquidez e dos riscos pertinentes a fatores
setoriais e conjunturas econômicas nacional e internacional. Por
meio de exemplos práticos e ilustrações, os autores exercitam os
conceitos teóricos abordados, desde os fundamentos básicos da
economia até a formulação de estratégias para investimentos de
longo prazo.

Compre agora e leia

Você também pode gostar