1. INTRODUÇÃO
A linguagem PL/I (Programming
Language One – Linguagem de
Programação Um) foi criada no final da década de 50. Segundo suas
características, é voltada para as áreas comercial, como por exemplo o COBOL (Common Business Oriented Language – Linguagem Comum Orientada
aos Negócios) e científica, como o Fortran (Formula Translator –
Tradutor de Fórmulas).
1.1. Folha de codificação PL/I
Na codificação PL/I, são consideradas apenas 80 colunas.
Porém, assim como o COBOL, haverá distinção de áreas na codificação por parte
do compilador. Observe a tabela abaixo:
Colunas
|
Funções
|
01
|
Controle de carro para Impressão
da listagem do fonte
|
02-72
|
Livre para descrever todo o
programa
|
73-80
|
Livre para sequenciar as linhas do
programa ou documentar
|
Explicações:
Ä
Durante a compilação do programa, será gerada
uma listagem. O caracter constante da coluna 1 determinará uma ação (saltar
página, por exemplo) a ser feita pelo compilador.
Ä
Todos os comandos da linguagem PL/I serão
efetivamente codificados nas colunas iniciadas pela 02, indo até a 72. Qualquer
instrução fora dessas colunas será ignorada.
Ä
As colunas de 73 a 80 são livres para qualquer
tipo de comentário, pois são ignoradas pelo compilador.
1.2. Identificadores
Os identificadores PL/I são regidos da seguinte maneira:
Ä
Pode conter apenas caracteres alfabéticos,
numéricos e hífen (-);
Ä
O primeiro caracter do identificador deverá ser
sempre alfabéticos;
Ä
Um identificador conterá no máximo 31
caracteres, havendo algumas exceções, como os nomes de procedimentos, que
conterão no máximo 31 caracteres.
1.3. Conjunto de caracteres
Existem dois conjuntos de caracteres que são disponíveis
para o PL/I: o de 48 e o de 60 caracteres. Isso se deve em virtude de
diferentes versões da linguagem. O PL/I
Básico utiliza o conjunto de 48 caracteres e as versões PL/I Full e Optimizing utilizam o conjunto de 60, mantendo compatibilidade com
o de 48.
Quando se usa o conjunto de 60 caracteres não há palavras
reservadas. No conjunto de 48, algumas são reservadas ao compilador para um fim
específico, como por exemplo LE, GT, etc.
Observe a distribuição dos conjuntos:
|
29 caracteres alfabéticos
|
De 60
|
10 caracteres numéricos
|
|
21 caracteres especiais
|
|
27 caracteres alfabéticos
|
De 48
|
10 caracteres numéricos
|
|
11 caracteres especiais
|
Conjunto de caracteres:
Classificação
|
60 caracteres
|
48 caracteres
|
Descrição
|
Alfanuméricos
|
A a
Z
$
@ e
#
|
A a
Z
$
Não
disponível
|
Alfabético
Alfabético
Alfabético
|
0 a
9
|
0 a
9
|
Numérico
|
|
Especiais
|
=
+
-
*
/
(
)
,
.
‘
%
:
;
¬
&
|
<
>
—
?
|
=
+
-
*
/
(
)
,
.
‘
//
..
.,.
NOT
AND
OR
LT
GT
Não
disponível
Não
disponível
|
Branco
Igual
Adição
Subtração
Multiplicação
- aster.
Divisão
- barra
Abre
parêntese
Fecha
parêntese
Vírgula
Ponto
Apóstrofo
Porcentagem
Dois
pontos
Ponto-e-vírgula
Não
lógico
E
lógico
Ou
lógico
Menor
que
Maior
que
Travessão
Interrogação
|
1.4. Comandos PL/I
Todos os comandos PL/I serão sempre codificados conforme a
sintaxe genérica a seguir:
<IDENTIFICADOR DE COMANDO> + <CORPO DE COMANDO>
+ <;>
Exemplo:
GOTO
SEGUE;
DCL
A DECIMAL FIXED;
Todas as linhas de comando lógicas PL/I serão
finalizadas com ponto-e-vírgula (;). Na impossibilidade de ser codificada
inteira em uma única linha física, basta passar para a de baixo e continuar a
codificação. Vírgulas (,) serão utilizadas em algumas estruturas que forem mais
extensas que uma linha, como por exemplo a instrução DECLARE que será vista
mais adiante. Mesmo assim o ponto-e-vírgula deverá estar obrigatoriamente
fechando a última linha.
Diferente do COBOL que admitia ponto apenas na última
instrução de uma section o parágrafo, todas as instruções PL/I sem exceção
deverão finalizar com ponto-e-vírgula.
1.5. Comentários
Os textos de comentário em PL/I serão delimitados por barra
– asterisco no início e asterisco – barra no final conforme a sintaxe a seguir:
/*
(texto de comentário) */
Os comentários podem conter várias linhas, sendo que sempre
serão respeitados os delimitadores.
2. VARIÁVEIS
A declaração das variáveis é feita através da setagem de
seus atributos. Observe a seguir os atributos para variáveis numéricas:
Atributo
|
Descrição
|
BASE
|
Se a variável é decimal ou binária
|
ESCALA
|
Se a variável é decimal ou binária
de ponto flutuante
|
MODO
|
Se a variável é real ou complexa
|
PRECISÃO
|
Grandeza da variável em relação ao
comprimento em bytes que ela ocupará na memória
|
2.1. Comando DECLARE
A linguagem PL/I é muito flexiva. Isto nos traz muitos
pontos positivos, mas também alguns inconvenientes. Um “problema” decorrido
desta flexibilidade é a não obrigatoriedade da declaração de variáveis. Isso
pode gerar problemas na documentação do programa, o que é muito desagradável
quando de sua manutenção. Por este motivo, no decorrer deste curso todas as
variáveis utilizadas em programas serão declaradas.
Outra flexibilidade da linguagem: diferente do COBOL, PL/I
não exige uma área especial para a declaração dos dados que serão utilizados
pelo programa. A qualquer ponto uma variável pode ser criada.
O comando DECLARE será utilizado para criar um identificador
através da definição de seus atributos. Podemos dizer que PL/I é uma linguagem tipada. Isso porque haverá uma série de
tipos de variáveis que serão utilizados para armazenar tipos diferentes de
informações. Nesta parte da apostila veremos os tipos mais utilizados e que nos
serão úteis no decorrer do curso.
Sintaxe:
DECLARE VARIÁVEIS E ATRIBUTOS
OBS: o comando DECLARE pode ser abreviado para DCL.
2.2. Real Decimal Fixed
Variável decimal de
ponto fixo com precisão (p,q), onde p é o número total de dígitos e q é o
número de dígitos da parte fracionária, sendo também chamado de fator de
escala.. Terá no máximo 15 dígitos com ou sem sinal.
Exemplos
DECLARE VALOR1
DECIMAL FIXED (4,1)
DCL VALOR2
DECIMAL FIXED (5,2)
2.3. Real Binary Fixed
Variável real e binária de ponto fixo com precisão (p,q).
Deve representar constantes que são strings de dígitos binários, com ou sem
ponto decimal, de no máximo 31 dígitos e seguidos pela letra B.
Exemplo:
DCL VALOR REAL BINARY FIXED (10,5)
OBS:
O atributo BINARY pode ser abreviado para BIN.
(p,q)
|
Exemplo de valor
|
(5,0) OU (5)
|
00110B
|
(7,4)
|
110.1100B
|
2.4. Real Decimal Float
Variável decimal, real de ponto flutuante e de precisão (p), onde p é o número de
dígitos significativos a ser considerado. Deve representar strings de dígitos
decimais, com ou sem sinal, de no máximo 16 dígitos seguidos por uma letra E,
indicativa do expoente na base 10 e seu respectivo expoente.
Por exemplo:
20.E3 = 20 x 103 = 20000
11E2 = 11 x 102 = 1100
(p)
|
Exemplo de valor
|
(6)
|
1.23456E+04
|
(3)
|
1.23E+04
|
2.5. Real Binary Float
Mesmas características do atributo visto anteriormente,
porém haverá um dígito B, no final da constante, especificando seu formato
binário
Exemplo:
1101.1E+04B = 11011000B
-1001.E-02B = -10.01B
2.6. Character
Variável caracter de
comprimento n, representando strings de caracteres. Estão limitadas a
32.767 bytes de comprimento.
Exemplo:
DECLARE NOME CHARACTER (40)
DCL ENDERECO CHAR (45)
2.7. Atributo Initial
Podendo ser abreviado para INIT, tal atributo serve para
inicializar as variáveis criadas, assim como a cláusula VALUE da linguagem
COBOL.
Exemplos:
DCL NOME CHAR(30) INIT(‘ ’),
VALOR DEC(3,2) INIT(0),
VLBIN BIN FIXED(4) INIT(1011B);
Observe que um único comando DECLARE pode ser utilizado para
declarar diversas variáveis normalmente.
2.8. Label
É uma variável especial, que poderá apenas assumir valores
de rótulos de comandos. Será utilizada durante a lógica do programa para
ocasionar desvios no fluxo de execução. Os valores (constantes labels)
armazenados em variáveis desse tipo somente poderão fazer referência a rótulos
do mesmo procedimento em que a variável foi declarada.
Com este recurso, pode-se criar situações semelhantes com o
GO TO DEPPENDING ON do COBOL.
Observe nos exemplos abaixo que as variáveis do tipo ainda podem utilizar uma
outra forma de inicialização de valores:
DCL ROT1 LABEL,
ROT2 LABEL INIT (GRAVA),
ROT3 LABEL(LE,GRAVA,REGRAVA),
ROT4
LABEL(LE,GRAVA,ORDENA,IMPRIME) INIT (LE);
O atributo LABEL permite ainda a especificação de quais
nomes de rótulos poderão ser armazenados pela variável durante a execução do
programa.
2.9. Declaração parcial de variáveis
Se faltar um mais atributos em um comando DECLARE, podemos
dizer que a variável foi parcialmente declarada e assumirá os atributos
defaults definidos pelo compilador conforme segue:
Ä
Se não for declarada a BASE ð será assumido DECIMAL
Ä
Se não for declarada a ESCALA ð será assumido FLOAT
Ä
Se não for declarado o MODO ð será assumido REAL
Ä
Se não for declarada a PRECISÃO ð
será assumido os defaults da tabela a seguir:
Base e Escala
|
Precisão
|
BINARY FIXED
|
(15,0)
|
DECIMAL FIXED
|
(5,0)
|
BINARY FLOAT
|
(21)
|
DECIMAL FLOAT
|
(6)
|
2.10. Variáveis não declaradas
Quando uma variável não é declarada, o compilador, ao
“perceber” uma movimentação, associação ou comparação desta variável irá
declará-la automaticamente seguindo as regras:
Ä
Toda e qualquer variável não declarada será numérica;
Ä
Se a primeira letra da variável for I, J,
K, L, M ou N, ela será uma half-word, binária,
sinalizada e de ponto flutuante;
Ä
Se não começar com uma das letras citadas, será
decimal de ponto flutuante, sinalizada com precisão de 6 casas na mantissa.
Sempre que tal situação ocorrer, o compilador irá avisar
informando que determinada variável não foi declarada explicitamente e está
sendo assumida como um tipo default.
2.11. Variáveis PIC (PICTURE)
Variáveis picture são numéricas, decimais zonadas e
sinalizadas ou não. são as mesmas PIC do COBOL, limitadas a 15 dígitos em PL/I.
Na verdade, trata-se de uma característica propositalmente semelhante à
linguagem COBOL, onde a sintaxe de declaração será:
DCL NÍVEL VARIÁVEL PIC ‘(nn)9V(nn)9’
As máscaras de impressão ‘Z’ para brancos, ‘,’
(vírgula),’.’ (ponto), ‘-’ (sinal negativo) e ‘+’ (sinal positivo) são válidas também.
Vale lembrar que o V que separa a
parte inteira da parte fracionária é apenas lógico, não ocupando espaço físico
na memória e não implica na impressão de uma vírgula ou ponto decimal quando a
variável é mostrada.
Observe as declarações a seguir:
Declaração
|
Descrição da variável
|
1)
PIC ‘9(15)’ ou PIC ‘(15)9’
|
2)
15 dígitos inteiros sem sinal
|
3)
PIC ‘V(15)9’ ou PIC ‘V9(15)’
|
4)
15 dígitos decimais sem sinal
|
5)
PIC ‘9(08)V9(07)’
|
6)
15 dígitos, 8 inteiros e 7 decimais sem sinal
|
7)
PIC ‘ZZZ.ZZ9’
|
8)
Máscara de impressão (não pode ser utilizada em
operações)
|
9)
PIC ‘S99.999’
|
10)
Máscara de impressão, indica se o número é positivo ou
negativo. O sinal aparecerá.
|
11)
PIC ‘+99.999’
|
12)
Máscara de impressão, só se número for positivo o
sinal “+” aparecerá.
|
13)
PIC ‘-99.999’
|
14)
Máscara de impressão, só se o número for negativo, o
sinal “-” aparecerá.
|
15)
PIC ‘99/99/999’
|
16)
Máscara de impressão utilizada para datas.
|
17)
PIC ‘99B99B9999’
|
18)
Máscara de impressão utilizada para datas.
|
Agora suponha o valor 123456789.012345 submetido às
pictures:
Picture
|
Resultado
|
1)
|
123456789
|
2)
|
012345
|
3)
|
23456789.012345
|
4)
|
+56.789
|
5)
|
+56.789
|
6)
|
+56.789
|
7)
|
56.789
|
8)
|
23/45/6789
|
9)
|
23 45 6789
|
3. COMANDOS DE ENTRADA E SAÍDA
3.1. Comando LIST
É um comando simples de E/S que permite a leitura de dados
para variáveis através do dispositivo de entrada padrão do sistema operacional
e a exibição de variáveis / expressões no dispositivo padrão de saída.
Sintaxe:
Para entrada ð GET LIST (lista de
variáveis);
Para saída ð
PUT LIST (lista de variáveis e/ou expressões);
Exemplos
GET LIST (A, B, C);
|
Lê três valores armazenando-os nas
variáveis A, B e C.
|
PUT LIST (‘O VALOR DE A ’, A);
|
Exibe a string entre apóstrofes,
seguido do conteúdo da variável A.
|
PUT PAGE;
|
Salta para a primeira linha da
página seguinte.
|
PUT PAGE LIST (‘LUIZ’);
|
Imprime a palavra LUIZ na primeira
linha da página seguinte.
|
PUT SKIP;
|
Salta uma linha.
|
PUT SKIP LIST (‘G&P’);
|
Salta uma linha e imprime G&P.
|
PUT SKIP (-1) LIST (‘BAURU’);
|
Posiciona o carro na primeira
coluna da linha atual e imprime a palavra BAURU
|
PUT LINE(15) LIST(‘SÃO PAULO’);
|
Imprime SÃO PAULO na 15a
linha da página
|
3.2. Comando EDIT
Semelhante ao comando anterior. A grande diferença é que o
comando EDIT permitirá que os dados sejam acompanhados de uma lista de formatos
para edição.
Sintaxe:
Para entrada ð GET EDIT (lista de variáveis) (lista de formatos)
(lista
de variáveis) (lista de formatos)
Para saída ð
GET EDIT (lista de variáveis) (lista de
formatos)
(lista
de variáveis) (lista de formatos)
A lista de formatos é uma lista de códigos, denominados
itens de FORMAT, separados por vírgula, que se referem a cada um dos tipos de
variáveis, em ordem. Teremos os itens de FORMAT DE CONTROLE, que são os mesmos
vistos no comando EDIT (PAGE, SKIP(n) e LINE(n)) e os itens de FORMAT DE DADOS
que são os responsáveis por determinar a maneira como os dados serão
apresentados.
Os itens de format de dados são:
a) PICTURE FORMAT ð
o formato é P‘especificação’, onde especificação corresponde ao atributo
PICTURE já visto antes.
Exemplo
DCL B DEC FIXED (6,2);
B = 1000;
PUT EDIT (B) (P‘9.999V,99´);
b) FIXED POINT FORMAT ð
a forma é F(w,d,p), onde w representa o tamanho do campo, d o número de dígitos que seguem o ponto
decimal e p um fator de escala,
podendo ser positivo ou negativo, representado multiplicar ou dividir o valor
inteiro por 10p. d e p são opcionais. Observe os exemplos:
Valor interno
|
FORMAT
|
Resultado
|
+2567.89
|
F(4)
|
2568
|
-2891.432
|
F(5)
|
-2891
|
-2891.432
|
F(7)
|
-2891
|
-2891.432
|
F(8,3)
|
2891.432
|
-2891.432
|
F(8,2)
|
-2891.43
|
+1234.5678
|
F(3)
|
235
|
-5641.21
|
F(11,3,2)
|
-564121.000
|
1204.129
|
F(10,1,2)
|
120412.9
|
c) FLOATING POINT FORMAT ð no formato E(w,d,s), onde w representa o comprimento do campo, d o número de dígitos que seguem o ponto decimal e s o número de dígitos que devem aparecer
antes do símbolo E, indicativo do expoente. Observe os exemplos:
Valor interno
|
FORMAT
|
Resultado
|
+397.7841
|
E(16,5)
|
397.78410E+00
|
+397.7841
|
E(16,6)
|
397.784100 E+00
|
+397.7841
|
E(16,7)
|
397.7841000 E+00
|
+397.7841
|
E(16,8)
|
397.78410000 E+00
|
+397.7841
|
E(16,9)
|
39.778410000 E+01
|
+397.7841
|
E(16,10)
|
3.9778410000E+02
|
+397.7841
|
E(16,11)
|
.39778410000E+03
|
+397.7841
|
E(16,10,12)
|
39.7784100000E+01
|
+397.7841
|
E(16,10,11)
|
3.9778410000E+02
|
+397.7841
|
E(16,10,10)
|
.3977841000E+03
|
d) CHARACTER STRING FORMAT ð cuja forma é A(w), onde w representa o comprimento do campo, cujo atributo foi declarado
como CHAR(n). Observe os exemplos a
seguir:
Valor interno
|
FORMAT
|
Resultado
|
‘ABCDEF’
|
A ou A(6)
|
ABCDEF
|
‘ABCDEF’
|
A(5)
|
ABCDE
|
‘ABCDEF’
|
A(8)
|
ABCDEF
|
‘BCD’
|
A(6)
|
BCD
|
‘ABCDEFGH’
|
A(3)
|
ABC
|
e) Format Remoto
Os formatos podem ser definidos em um rótulo de comando para
serem utilizados em outras partes (remotamente) do programa. O formato será R(label). Observe os exemplos:
FORMATO:
FORMAT(A(5),SKIP,F(7,4),F(4));
...
GET
EDIT(V1,V2,V3) (R(FORMATO));
...
PUT
LINE(5) EDIT (A,B,C) (R(FORMATO));
4. BLOCOS
4.1. Procedure (procedimento)
São blocos de instruções que podem receber valores como
argumentos através de uma área de entrada, realizar um determinado
processamento e ainda retornar valores
ao procedimento chamador através de uma área de saída. Funcionam de forma
bastante semelhante aos programas chamados com a instrução CALL do COBOL (em
PL/I o comando de chamada também será CALL). Veremos mais tarde informações
detalhadas sobre procedimentos.
4.2. Procedimento principal
Todo programa escrito em PL/I apresentará obrigatoriamente
um procedimento principal que será automaticamente invocado pelo sistema
operacional depois que o programa foi compilado. Este procedimento poderá
invocar outros em tempo de execução.
O formato da procedure principal que iniciará o programa
será sempre:
Todos os comandos do programa serão codificados após esta
linha de declaração. Ao final dos comandos o procedimento principal deve ser
encerrado utilizando o formato a seguir:
END ;
Todos os demais procedimentos que forem codificados no
programa deverão estar antes do END da procedure principal.
Para exemplificar o que foi dito, suponha a codificação de
um programa chamado PROG01 conforme segue:
PROG01: PROCEDURE (PARM)
OPTIONS (MAIN);
PUT SKIP(‘OLA, BEM VINDOS A G&P’);
END PROG01;
Explicação:
Ä
PROG01 ð É o nome do
programa identificado na JCL, devendo conter no máximo 07 caracteres,
corresponde à procedure principal;
Ä
PROCEDURE
OPTIONS (MAIN) ð
Deve ser o primeiro comando obrigatório do programa. A palavra chave
PROCEDURE pode ser abreviada para PROC.
Ä
(PARM) ð São parâmetros
passados pelo cartão JCL. Sua codificação é opcional.
Ä
END ð Indica o término
do programa. É obrigatório, devendo sempre ser indicado o nome.
4.3. Blocos de comandos
Um bloco é uma seqüência de comandos que define uma área do
programa. Será utilizado em diversos comandos e estruturas do programa e poderá
assumir um dos formatos a seguir:
DO;
COMANDO 1;
COMANDO 2;
...
COMANDO N;
END;
ou
BEGIN;
COMANDO 1;
COMANDO 2;
...
COMANDO N;
END;
A utilização de um destes dois conjuntos dependerá do
comando ou estrutura utilizado.
4.4. Label ou Rótulo de comando
Não é considerado um componente de comando. Pode ser utilizado
pelo programador simplesmente para identificar partes de uma programa ou causar
desvios com o comando GOTO. O rótulo em um programa será sempre seguido de dois
pontos (:) e sem espaços, conforme formato a seguir:
CALCULA:
A = B + 1;
C = A * B / 2 + D;
4.5. Desvios
Em um procedimento PL/I os comandos são executados na
seqüência em foram codificados. Havendo vários labels, estes também terão seus
comandos executados em ordem sequencial.
No entanto, o fluxo de execução do programa pode
perfeitamente ser alterado através de comandos que ocasionam desvios.
4.6. Comando GOTO
O comando GOTO será utilizado para ocasionar um desvio
incondicional do ponto que está sendo executado do programa para um outro label
especificado.
Sintaxe:
GOTO
Lembre-se que GOTO é um comando de programação linear e fere
as regras de programação estruturada, pela simples configuração de lógica
desta. Assim sendo, pode ser eventualmente utilizado, desde que com
disciplina, sem que não prejudique a clareza e o bom entendimento da lógica
do programa.
4.7. Comando CALL
Desvia o fluxo de
execução para a procedure especificada, retornando para a linha imediatamente
posterior à chamada.
Sintaxe:
CALL ;
O procedimento será codificado da seguinte maneira:
COMANDO
1;
COMANDO
2;
...
COMANDO
N;
END ;
As variáveis definidas no procedimento principal do programa
poderão ser normalmente utilizadas nas demais procedures.
Exemplo:
PROG02: PROC OPTIONS (MAIN);
DCL
(A, B, C) FIXED(4);
CALL
ACESSA;
C
= A + B;
PUT
SKIP(2) LIST(A, B);
ACESSA: PROC;
GET LIST(A, B);
END ACESSA:
END PROG02;
Observe no exemplo dado, um estilo diferente de declaração
de variáveis. As variáveis são todas colocadas entre parênteses, separadas por
vírgula e depois os atributos são codificados.
4.8. Procedimento com argumentos
Argumentos (também chamados de parâmetros) são valores
enviados para um procedimento afim de serem processados e resultar em um novo
valor.
Os procedimentos em PL/I recebem informações de forma
semelhante ao COBOL. São declaradas diversas variáveis que serão utilizadas
como:
Área de entrada ð utilizada para o
envio de informações ao procedimento.
Área de saída ð utilizada para
obter o resultado do processamento pelo procedimento.
O comando RETURN é colocado antes do END da procedure. Pode
ser considerado seu fim lógico e a formatação dos parâmetros de saída.
Sintaxe:
Na chamada:
CALL PROCEDIMENTO(A1,A2,A3,
...,AN);
No procedimento:
PROCEDIMENTO: PROC(A1, A2,
A3,..., AN);.
DCL
A1, A2, ..., AN
...
RETURN;
END PROCEDIMENTO;
Exemplo:
PROG03: PROC OPTIONS (MAIN);
DCL
(A, B, C) FIXED(5);
GET
LIST(A,B);
CALL
SOMA(A, B,C);
PUT
LIST (C);
SOMA
PROC(P1,P2,P3);
DCL
(P1,P2,P3) FIXED(5);
P3
= P1 + P2;
RETURN;
END
SOMA;
END PROG03;
4.9. Funções
São parecidas com os procedimentos. Será diferente a maneira
como os argumentos serão enviados e como o resultado será recebido. Neste caso,
faremos uso do comando RETURN, para enviar um valor de volta ao procedimento
chamador.
O comando RETURN tem a sintaxe:
RETURN (VARIÁVEL) ou RETURN
(EXPRESSÃO)
Observe o exemplo:
PROG04: PROC OPTIONS (MAIN);
DCL (A, B, C) FIXED (5);
GET
LIST (A,B);
C
= SOMA(A,B);
SOMA:
PROC(P1,P2);
DCL
(P1,P2) FIXED(5);
RETURN
(P1 + P2);
SOMA
END;
END PROG04;
Nenhum comentário:
Postar um comentário