Tópicos em LP. Fabio Mascarenhas

Documentos relacionados
Compiladores II. Fabio Mascarenhas

Compiladores II. Fabio Mascarenhas

Compiladores II. Fabio Mascarenhas

Tópicos em LP. Fabio Mascarenhas

Descobrindo Lua. Sérgio Queiroz de Medeiros. Campus Party LabLua. Sérgio Queiroz de Medeiros Descobrindo Lua 1

A Linguagem Lua Lua Puc-Rio

Compiladores II. Fabio Mascarenhas

Tópicos em LP. Fabio Mascarenhas

Programação I Aula 17 Correção de programas Pedro Vasconcelos DCC/FCUP

MAB TINY na LVM. Wednesday, November 30, 11

Linguagem Python. Processamento Estatístico da Linguagem Natural. Barra invertida em strings. Strings. Aspas triplas. Operações com Strings

Compiladores - Análise Léxica

Prof. Esp. Andrew Rodrigues 1

Linguagem de Programação e Compiladores

Compiladores - Análise Léxica

Estruturas de Dados em Python

Lua. mais uma linguagem dinâmica. linguagem de descrição de dados. ênfase em scripting. alguma similaridade com Python, Perl, e outras

Introdução à Programação Aula 17 Deteção e correção de erros

Nesta aula... Diagramas da stack. Recursão. 1 Funções. 2 Valores booleanos e condicionais. 3 Execução condicional e recursão

Linguagem Python. Inteligência Artificial. Características de Python. Importando módulos. Módulos. Usando Python no modo interativo

Linguagens de Programação

Introdução à Programação / Programação I

3. Linguagem de Programação C

Linguagens de Domínio Específico

LUA. Carlos Henrique Maulaz de Freitas Matheus Beloti Mariani Thiago Gozzi Renoldi Siqueira Costa

Aula de hoje. Comandos. Comandos simples. Comandos. Comandos de controle. Bloco de comandos. SCC Introdução à Programação para Engenharias

4. Constantes. Constantes pré-definidas

MCG126 Programação de Computadores II

Linguagens de Domínio Específico

Linguagens de Domínio Específico

Python: Exceções, Iteradores e Geradores. Claudio Esperança

Lua Parte I. Overview. Linguagem pequena; Sintaxe simples e clara; Gerenciamento automático de memória; Execução controlada; Tipagem dinâmica.

LEONARDO SANTOS PAULUCIO LUIZ GUILHERME LITTIG BERGER

Seleção Múltipla Laços (while, do-while, for) AULA 05

LUA. Deise Miranda Douglas Neves Luane Gomes Naara Soares

Compiladores - Especificando Sintaxe

Construtores e Especificadores de Acesso

Introdução a classes e objetos. Prof. Marcelo Roberto Zorzan Prof a. Rachel Reis

Análise de Programação

Variáveis primitivas e Controle de fluxo

Variáveis e Entrada de Dados Marco André Lopes Mendes marcoandre.googlepages.

Lua. mais uma linguagem dinâmica. linguagem de descrição de dados. ênfase em scripting. alguma similaridade com Python, Perl, e outras

Compiladores - Análise Recursiva

Python - Variáveis e expressões

Paradigmas de Programação

Compiladores - Análise Recursiva

Implementando classes em C# Curso Técnico Integrado em Informática Fundamentos de Programação

Introdução ao Scilab

Prof. Natalia Castro Fernandes Mestrado em Telecomunicações UFF 2º semestre/2012

Linguagens de Programação. Programação Funcional e Haskell Programação Interativa Thiago Alves

Compiladores II. Fabio Mascarenhas

O Common Language Runtime (CLR) é uma plataforma criada com o objetivo de facilitar a interoperabilidade entre diferentes linguagens de programação,

Linguagem de Programação II Implementação

Prof. A. G. Silva. 28 de agosto de Prof. A. G. Silva INE5603 Introdução à POO 28 de agosto de / 1

Compiladores - JFlex. Fabio Mascarenhas

Compiladores - JFlex. Fabio Mascarenhas Monday, April 15, 13

Organização de programas em Python. Vanessa Braganholo

PROGRAMAÇÃO de COMPUTADORES: LINGUAGEM FORTRAN 90/95

Computação 1 - Python Aula 10 - Teórica: Estrutura de Dados - Dicionário. João Carlos, Carla Delgado, Ana Luisa Duboc 1/ 18

Paradigmas de Programação. Java First-Tier: Aplicações. Orientação a Objetos em Java (I) Nomenclatura. Paradigma OO. Nomenclatura

Programação de Computadores II

WEBDESIGN. Professor: Paulo Marcos Trentin - Escola CDI de Videira

Dados armazenados em um objeto podem ser tanto primitivos, tais como inteiros ou caracteres, ou referências para outros objetos.

Construção de Sites 2. Prof. Christiano Lima Santos

Linguagem de Programação III - PHP

Introdução ao SciLab. SciLab O que é? Onde obter o programa:

Introdução à Programação em C. Prof. Ricardo Teixeira Tecnologia em Mecatrônica Industrial SENAI

Introdução à Linguagem Lua Variáveis e Expressões

Listas, conjuntos e dicionários

Minicurso de Python Aula 2. Raphael Lupchinski Marcelo Millani

Programação I Aula 3 Primeiros programas

1 Definição de funções 1. 2 Valores boleanos e condicionais 5. Podemos depois usar as novas funções tal qual as pré-definidas

3.1 - Funções para manipular dados de entrada e saída padrão

AULA 2: INTRODUÇÃO A PYTHON. Luís Feliphe Silva Costa

Funções são blocos de código que podem ser nomeados e chamados de dentro de um programa.

Tópicos em LP. Fabio Mascarenhas

Computação II (MAB 225)

Classes e Objetos. Sintaxe de classe em Java

Vetores. IFSC/Florianópolis - Programação Orientada a Objetos + POO - prof. Herval Daminelli

Minicurso de JavaScript PET Sistemas de Informação Terceiro Dia Anthony Tailer. Clécio Santos. Rhauani Fazul.

Compiladores Análise Semântica

Computação 1 - Python Aula 2 - Teórica. João Carlos, Carla Delgado, Ana Luisa Duboc 1/ 39

Histórico. Perl (Practical Extraction and Report Language). Criada por Larry Wall em 1987.

Compiladores Geração de Código

Funções. Prof. Alberto Costa Neto Programação em Python

Compilação da linguagem Panda

Algoritmos e Programação

Identificadores Nome de variáveis, constantes, métodos, etc...

Compiladores. Bruno Lopes. Bruno Lopes Compiladores 1 / 31. Instituto de C

INSTRUÇÕES DE REPETIÇÃO

Computação I - Python

Programação C/C++ Slide 5 Nielsen Castelo Damasceno

Introdução à Programação C

Lua. Simple things simple, complex things possible. André Martinelli, Breno Krohling, Israel Santos, Matheus Vieira, Pedro Henrique Flores

Prática 10 - Funções

Transcrição:

Tópicos em LP Fabio Mascarenhas 2018.1 http://www.dcc.ufrj.br/~fabiom/comp2

Tabelas para tudo Tabelas são o único tipo estruturado de Lua Elas podem representar vetores, conjuntos, registros, objetos, e outras estruturas de dados de maneira eficiente, e com suporte sintático As operações básicas são construção ({}), para criar uma nova tabela, e indexação ([]), para ler e escrever valores > tab = {} -- cria nova tabela, associa a tab > tab["x"] = 5 -- escreve 5 no campo x > print(tab["x"]) -- lê valor do campo x e imprime 5 Tabelas são um tipo mutável por referência, então têm os mesmos problemas de aliasing de objetos Java e pointeiros C > alias = tab > alias["x"] = "mudou" > print(tab["x"]) mudou

Conjuntos Um jeito elegante de representar conjuntos em Lua é com uma tabela onde as chaves são os elementos do conjunto, e os valors são true O teste de pertinência no conjunto vira uma indexação, e também podemos acrescentar e remover elementos indexando a tabela Uma terceira sintaxe para o construtor é útil para inicializar conjuntos: -- conjunto de quarto números inteiros aleatórios de 1 a 10 local set = { [math.random(10)] = true, [math.random(10)] = true, [math.random(10)] = true, [math.random(10)] = true } Substituindo true por um número temos um multiconjunto, onde cada elemento pode aparecer mais de uma vez

Iterando com pairs Um laço for usando a função embutida pairs itera sobre todas as chaves e valores de uma tabela: local tab = { x = 5, y = 3, 10, "foo" } for k, v in pairs(tab) do print(tostring(k).. " = ".. tostring(v)) Como em ipairs, a primeira variável de controle recebe as chaves, a segunda os valores Tabelas são tabelas hash, então pairs não garante a ordem de iteração; use sempre ipairs para iterar sobre um vetor Mas pairs é ótimo para iterar sobre um conjunto, usando _ como variável de controle para os valores

Quiz Qual a saída do programa abaixo? sunday = "monday"; monday = "sunday" t = { sunday = "monday", [sunday] = monday } print(t.sunday, t[sunday], t[t.sunday])

Exercício - tokenizador A função token deve receber uma string, pular os espaços iniciais, e retornar o tipo do primeiro token, seu lexema e o restante da string Palavras reservadas: function,, while, local, true, and, false, else, if, elseif, not, nil, or, return, then, do Numerais: inteiros Strings: aspas duplas, código de escape \ Operadores: +, -, *, /, ==, ~=, <, =, (, ), {, },.,,,..,... Identificadores

Erros Funções Lua têm duas maneiras de sinalizar erros: retornar nil e uma mensagem de erro, ou lançar um erro A primeira maneira é para quando os erros são esperados, quando estamos abrindo um arquivo, por exemplo, já que sempre há o risco do arquivo não existir: > print(io.open("notafile.txt")) nil notafile.txt: No such file or directory 2 A segunda maneira é para problemas excepcionais, quando há erros na entrada, ou bugs no código: > print(math.sin("foo")) stdin:1: bad argument #1 to 'sin' (number expected, got string) stack traceback: [C]: in function 'sin' stdin:1: in main chunk [C]: in?

De mensagens de erro para erros A função embutida assert transforma erros do primeiro tipo em erros do segundo: > print(assert(io.open("foo.txt"))) file (000007FF650BE2D0) > print(assert(io.open("notafile.txt"))) stdin:1: notafile.txt: No such file or directory stack traceback: [C]: in function 'assert' stdin:1: in main chunk [C]: in? A função embutida error recebe uma mensagem e lança um erro: > error("raising an error") stdin:1: raising an error stack traceback: [C]: in function 'error' stdin:1: in main chunk [C]: in?

Divisão inteira, com e sem erros As duas implementações da função idiv abaixo mostram as duas maneiras de reportar erros: function idiv1(a, b) if b == 0 then return nil, "division by zero" else return math.floor(a/b) function idiv2(a, b) if b == 0 then error("division by zero") else return math.floor(a/b) > print(idiv1(2,0)) nil division by zero > print(idiv2(2,0)) stdin:3: division by zero stack traceback: [C]: in function 'error' stdin:3: in function 'idiv2' stdin:1: in main chunk [C]: in?

Capturando erros Lançar um erro aborta a execução por default; se estivermos no REPL voltamos ao prompt Podemos capturar e tratar erros usando a função embutida pcall, que recebe uma função para chamar e seus argumentos, retornando: true seguido dos resultados da função, se não houve erros false seguido da mensagem de erro, se houve um erro > print(pcall(idiv2, 5, 2)) true 2 > print(pcall(idiv2, 5, 0)) false division by zero

Módulos Até agora estivemos trabalhando no REPL e no context de um único script Também estivemos usando funções embutidas como ipairs e table.concat Mas a maior parte das aplicações fica melhor distribuída em vários scripts, e não usam apenas as funções embutidas Módulos resolvem tanto o problema do compartilhamento quanto do reuso de código; um modulo é um grupo reusável de funções e estruturas de dados relacionadas

Módulos são tabelas Um módulo Lua é um pedaço de código que cria e retorna uma tabela; essa tabela tem todas as funções e estruturas de dados que o módulo exporta A biblioteca padrão define vários módulos embutidos: table, io, string, math, os, coroutine, package e debug Uma aplicação carrega um módulo com a função embutida require; ela recebe o nome de um pacote, e retorna um módulo A aplicação deve atribuir o módulo retornado por require a uma variável, já que require por si só não faz nenhuma atribuição

Um pacote simples Um pacote é um script Lua que cria e retorna um módulo; como exemplo, vamos criar um módulo simples para números complexos em um pacote complex.lua no mesmo path onde estamos rodando nosso REPL: local M = {} function M.new(r, i) return { real = r or 0, im = i or 0 } M.i = M.new(0, 1) function M.add(c1, c2) return M.new(c1.real + c2.real, c1.im + c2.im) function M.tostring(c) return tostring(c.real).. "+".. tostring(c.im).. "i" return M

Outro estilo Podemos definir o mesmo módulo em um estilo diferente: local function new(r, i) return { real = r or 0, im = i or 0 } local i = new(0, 1) local function add(c1, c2) return new(c1.real + c2.real, c1.im + c2.im) local function tos(c) return tostring(c.real).. "+".. tostring(c.im).. "i" return { new = new, i = i, add = add, tostring = tos } Esse estilo tem melhor desempenho, mas mais duplicação; é questão de gosto

Carregando o pacote complex Podemos carregar nosso novo pacote no REPL: > complex = require("complex") > print(complex) table: 0000000000439820 Se chamarmos require novamente recebemos nosso módulo cacheado: > print(require("complex")) table: 0000000000439820 Para forçar a recarga do pacote limpamos o módulo do cache: > package.loaded.complex = nil > complex = require("complex") > print(complex) table: 000000000042F8F0

Usando o módulo Uma vez que temos o módulo em uma variável, podemos usar qualquer coisa que ele exporta: > c1 = complex.new(1, 2) > print(complex.tostring(c1)) 1+2i > c2 = complex.add(c1, complex.new(10,2)) > print(complex.tostring(c2)) 11+4i > c3 = complex.add(c2, complex.i) > print(complex.tostring(c3)) 11+5i Um módulo é uma tabela, então poderíamos atribuir a seus campos e substituir suas funções (monkey-patching), mas isso não é um estilo de programação recomado em Lua

Procurando pacotes Onde require procura o pacote complex.lua? Ele usa um caminho de busca na variável package.path: > print(package.path) /usr/local/share/lua/5.3/?.lua;/usr/local/share/lua/5.3/?/init.lua;/usr/local/li b/lua/5.3/?.lua;/usr/local/lib/lua/5.3/?/init.lua;./?.lua O caminho de busca depe do sistema, e vem por default da variável de ambiente LUA_PATH_5_3, se definida, ou LUA_PATH, ou um valor pré-compilado no interpretador O caminho de busca é uma lista de modelos separados por ponto-e-vírgula; require tenta cada modelo em sequência, substituindo? pelo nome do pacote

Procurando complex Para o caminho de busca no slide anterior, require vai tentar os seguintes caminhos: /usr/local/share/lua/5.3/complex.lua /usr/local/share/lua/5.3/complex/init.lua /usr/local/lib/lua/5.3/complex.lua /usr/local/lib/lua/5.3/complex/init.lua./complex.lua Como complex.lua está no caminho corrente o último é bem sucedido Podemos usar a função package.searchpath para ver qual pacote será carregado para determinado nome e caminho de busca: > print(package.searchpath("complex", package.path)).\complex.lua

Conflitos Suponha que temos dois pacotes complex.lua em nosso sistema, mas eles significam coisas diferentes, ou implementações diferentes da mesma coisa, e queremos ter as duas Podemos por cada pacote em sua própria pasta; por exemplo, o primeiro em adts/complex.lua, e o segundo em numlua/complex.lua Podemos fazer require "adts.complex" para carregar o primeiro, e require "numlua.complex" para o segundo Lua substitui os pontos pelo separador de caminho do sistema antes de começar a procura pelo pacote > print(package.searchpath("adts.complex", package.path)) nil no file '/usr/local/share/lua/5.3/adts/complex.lua' no file '/usr/local/share/lua/5.3/adts/complex/init.lua' no file '/usr/local/lib/lua/5.3/adts/complex.lua' no file '/usr/local/lib/lua/5.3/adts/complex/init.lua' no file './adts/complex.lua'

Iterando sobre... Podemos usar... dentro de um constructor de tabela, e assim iterar sobre os argumentos extras de uma função variádica: function add(...) local sum = 0 for _, n in ipairs({... }) do sum = sum + n return sum Se algum dos argumentos extras for nil então {... } não será um vetor. A função table.pack junta todos os seus argumentos, inclusive nils, em uma tabela, e escreve o número de argumentos no campo n : > t = table.pack(1, nil, 3) > for i = 1, t.n do print(t[i]) 1 nil 3

table.unpack A inversa de table.pack é a função table.unpack: > print(table.unpack({ 1, 2, 3, 4 })) 1 2 3 4 Da maneira acima, table.unpack só funciona com vetores sem buracos Para vetores com buracos, table.unpack aceita mais dois argumentos, que dão os índices inicial e final do intervalo retornado por table.unpack: > a = { [2] = 5, [5] = 0 } > print(table.unpack(a, 1, 5)) nil 5 nil nil 0

Argumentos nomeados Pode-se simular uma função que recebe parâmetros nomeados passando um registro: function rename(args) return os.rename(args.old, args.new) Lua tem um pouco de suporte sintático para esse uso; se o único argumento de uma função for um construtor, os parênteses podem ser omitidos: rename{ new = "perm.lua", old = "temp.lua" }

Escopo léxico Qualquer variável local visível no ponto em que uma função é definida também é visível dentro da função, podo inclusive ser modificada: function derivative(f, dx) dx = dx or 1e-4 return function (x) -- tanto f quanto dx visíveis! return (f(x + dx) - f(x)) / dx A função derivative recebe uma função e retorna outra função, e é um exemplo de função de alta ordem: > df = derivative(function (x) return x * x * x ) > print(df(5)) 75.001500009932

Fechos Dizemos que uma função se fecha sobre as variáveis locais que ela usa, então chamamos essas funções de fechos (closures) Um fecho pode tanto ler quanto escrever as variáveis locais que ela se fechou sobre: function counter() local n = 0 return function () n = n + 1 return n Cada chamada a counter() cria um novo fecho > c1 = counter() > c2 = counter() > print(c1()) 1 > print(c1()) 2 > print(c2()) 1 Cada fecho se fecha sobre uma instância diferente de n

Fechos e compartilhamento Fechos se fecham sobre as próprias variáveis, e não sobre cópias delas, então dois fechos podem compartilhar uma variável: function counter() local n = 0 return function (x) n = n + (x or 1) return n, function (x) n = n - (x or 1) return n counter() agora retorna dois fechos com o mesmo n > inc, dec = counter() > print(inc(5)) 5 > print(dec(2)) 3 > print(inc()) 4

Callbacks Fechos são um bom mecanismo para callbacks; por exemplo, table.sort recebe como parâmetro opcional um callback para comparar os elementos do vetor: > a = { "Python", "Lua", "C", "JavaScript", "Java", "Lisp" } > table.sort(a, function (a, b) return a > b ) > print_array(a) { Python, Lua, Lisp, JavaScript, Java, C }