Compiladores LEIC Alameda 2 o Semestre 2009/2010 Linguagem Pipoca Manual de Referência 29 de Março de 2010

Documentos relacionados
Compiladores LEIC Alameda 2 o Semestre 2009/2010 Linguagem Pipoca Manual de Referência 5 de Abril de 2010

Compiladores LEIC Alameda 2 o Semestre 2009/2010 Linguagem Pipoca Manual de Referência 22 de Março de 2010

1 Tipos de dados. 2 Manipulac~ao de nomes

Projecto de Compiladores LEIC-A 2007/2008 (2 o Semestre) Linguagem NX6 Manual de Referência 4 de Março de 2008

1 Tipos de dados. 2 Manipulac~ao de nomes. Projecto de Compiladores Ano lectivo 2012/2013, 2 o Semestre

Compiladores (LEIC-A 2 o Semestre 2008/2009) Linguagem S9 Manual de Referência 16 de Março de 2009

1 Características Básicas

Estruturas da linguagem C. 1. Identificadores, tipos primitivos, variáveis e constantes, operadores e expressões.

PROGRAMAÇÃO I E N T R A DA E S A Í DA D E DA D O S

Revisão da Linguagem C Prof. Evandro L. L. Rodrigues

Algoritmos e Estruturas de Dados I (DCC/003) Estruturas Básicas. Aula Tópico 2

Elementos Básicos. C# - Elementos básicos. Primeiro programa Tipos de dados Variáveis Constantes Expressões e operadores Controlo de fluxo Tabelas

Linguagem de Programação I. Aula 06 Linguagem C: Tipos de Dados

Algoritmos e Estruturas de Dados I (DCC/003) 2013/1. Estruturas Básicas. Aula Tópico 4

Linguagem Java - Introdução

A Linguagem C. A forma de um programa em C

Hello World. Linguagem C. Tipos de Dados. Palavras Reservadas. Operadores Aritméticos. Pré e pós incremento e pré e pós decremento

Operadores. Tipo de operadores. Aritméticos. Relacionais. Lógicos. Bit a bit. Cálculos aritméticos: soma, subtracção, multiplicação, divisão, etc.

Referências. Linguagem C. Tipos de variáveis em XC8. Tipos de variáveis. Tipos de variáveis em XC 8 Exemplo. Radicais numéricos em C

Operadores e separadores Identificadores Palavras chave Constantes

ALGORITMOS E APLICAÇÕES. FATEC IPIRANGA ADS Noturno 1º semestre de 2012 Prof. Luiz Carlos de Jesus Junior

PROGRAMAS BÁSICOS EM C++ Disciplina: Introdução à Ciência da Computação Prof. Modesto Antonio Chaves Universidade estadual do Sudoeste da Bahia

#include <stdio.h> Void main() { printf( Cheguei!\n"); } INTRODUÇÃO A LINGUAGEM C

K&R: Capitulo 2 IAED, 2012/2013

PROGRAMAÇÃO ESTRUTURADA E ORIENTADA A OBJETOS

Objectivos. Observar os tipos fornecidos pelo C++ Explicar as regras sintácticas para nomes de identificadores Estudar variáveis e constantes

Aula 4 - Operadores. Prof. Laura Silva de Assis. Engenharia de Computação 2 o Período

Capítulo 2 Operadores. A função scanf()

A linguagem C (visão histórica)

Controlo de Execução. K&R: Capitulo 3

A linguagem algorítmica utiliza o português para a definição dos comandos e tem as seguintes característica:

Métodos Computacionais. Operadores, Expressões Aritméticas e Entrada/Saída de Dados

Algoritmos e Estruturas de Dados I IEC012. Linguagem C - Guia de bolso - Prof. César Melo

Linguagem C: Introdução

Noçõ linguagem Java. Profs. Marcel Hugo e Jomi Fred Hübner. Departamento de Sistemas e Computação Universidade Regional de Blumenau - FURB

Diagramas Sintáticos

4. Constantes. Constantes pré-definidas

Variáveis primitivas e Controle de fluxo

SEBENTA INTRODUÇÃO Á ALGORITMIA

Programação de Computadores I Introdução ao C PROFESSORA CINTIA CAETANO

Introdução ao Fortran 90-1

Computação Eletrônica. Tipos de dados, constantes, variáveis, operadores e expressões. Prof: Luciano Barbosa

1/50. Conceitos Básicos. Programa Básico

3. Linguagem de Programação C

PORTUGUÊS ESTRUTURADO: INTRODUÇÃO INTRODUÇÃO À PROGRAMAÇÃO PROF. ALEXANDRO DOS SANTOS SILVA

Algoritmos. Algoritmos e Linguagem de Programação - Prof Carlos Vetorazzi

Programação Estruturada

Compilação da linguagem Panda

Tipos Primitivos, estruturas de iteração e decisão.

Linguagens de Programação I

Princípios de Desenvolvimento de Algoritmos MAC122

C Operadores e Expressões

Java 2 Standard Edition Tipos, literais, operadores e controle de fluxo

Introdução à Computação MAC0110

AMBIENTE DE PROGRAMAÇÃO PYTHON II

Capítulo 1: Introdução à Linguagem C. Pontifícia Universidade Católica Departamento de Informática

LÓGICA DE PROGRAMAÇÃO. PROFª. M.Sc. JULIANA H Q BENACCHIO

7 Operadores e Expressões

TÉCNICO DE INFORMÁTICA - SISTEMAS

Descrição da Linguagem DECAF

Introdução à Programação em C Input / Output

Engenharia Elétrica AAM. Professor: Marco Shawn Meireles Machado

Programação com Acesso a BD. Programação com OO Acesso em Java

Programação de Computadores III

Algoritmos II prof. Daniel Oliveira

Aula 03: Introdução a C

Introdução à programação em PASCAL. Aula de 22/10/2001. Nota: Conjunto de slides baseados nas transparências utilizadas em PEDA em anos anteriores

Linguagem C: Variáveis e Operadores. Prof. Leonardo Barreto Campos 1

Programação de Computadores III

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

11 - Estrutura de um programa em C

Conceitos básicos de programação

Funções getchar() e putchar()

Programação I A Linguagem C. Prof. Carlos Alberto

Programação de Computadores

LÓGICA DIGITAL - CONCEITOS. * Constantes. * Expressões: Aritméticas; Lógicas; Tabela Verdade; Relacionais; Booleanas. * Portas Lógicas.

LINGUAGEM DE PROGRAMAÇÃO C AULA 2. Professor: Rodrigo Rocha

TASM DEFINIÇÃO DE UMA NOVA TABELA DE CONVERSÃO

4. Estruturas Fundamentais de Programação em C

Programação. MEAer. Expressões e Instruções. Bertinho Andrade da Costa. Instituto Superior Técnico. 2011/2012 1º Semestre

Conceitos Básicos de C

3. Linguagem de Programação C

EXPRESSÕES BOOLEANAS. Ex: boolean b = false; // declara uma variável do tipo boolean e atribui false

Sistemas Operacionais e Introdução à Programação. Programação com linguagem C

Puca Huachi Vaz Penna

Paradigmas de Linguagens de Programação. Expressões e Instruções de Atribuição

Introdução à Programação. Operadores, Expressões Aritméticas e Entrada/Saída de Dados

ECT1203 Linguagem de Programação

Introdução à Ciência da Computação scc-120

Linguagem C. André Tavares da Silva.

Lição 4 Fundamentos da programação

Introdução à Programação em C

6 Alguns conceitos e comandos em programação

Métodos de Programação I Ana Maria de Almeida

Programação de Computadores I Dados, Operadores e Expressões PROFESSORA CINTIA CAETANO

Desenvolvido por: Juarez A. Muylaert Filho - Andréa T. Medeiros - Adriana S. Spallanzani -

Aula 4: Bases Numéricas

Linguagens de Programação PROGRAMAÇÃO DE COMPUTADORES. Linguagem C. Linguagem C Estrutura Básica. Constante (literais) Linguagem C Primeiro Programa

Ambiente de desenvolvimento

Aula 5 Oficina de Programação Introdução ao C. Profa. Elaine Faria UFU

Transcrição:

Compiladores LEIC Alameda 2 o Semestre 2009/2010 Linguagem Pipoca Manual de Referência 29 de Março de 2010 Classificação mínima no projecto: 9,50 valores (sem arredondamentos) (40% da nota final). Fraudes na execução do projecto terão como resultado a classificação de 0 (zero) valores e consequente reprovação no ano lectivo 2009/2010, sem prejuízo de outras acções disciplinares pelos órgãos do IST. Datas: 2010/05/03 12:00 (entrega intermédia); 2010/05/31 12:00 (entrega final); 2010/06/15 2010/06/17 (teste prático). Dúvidas que não possam ser esclarecidas presencialmente ou através do material no Fénix, devem ser colocadas através de correio electrónico (ver ereço no Fénix). Adverte-se contra o uso de fontes de informação não oficiais. Este documento não descreve a linguagem formalmente, preferindo-se uma exposição intuitiva (em português). 1 Introdução A linguagem Pipoca é imperativa, não estruturada e fortemente tipificada. Um dos objectivos da linguagem é permitir a fácil leitura, pelo que é fortemente restritiva relativamente ao aspecto e à posição do código nas linhas (indentação). 1.1 Tipos de dados manipuláveis Números inteiros Designados por int, ocupam 4 bytes em complemento para dois, alinhados a 32 bits. Quando se omite o tipo, em situações onde é normalmente necessário, assume-se o tipo inteiro (ver abaixo). Números reais Designados por real, ocupam 8 bytes em vírgula flutuante (norma IEEE 754). Cadeias de caracteres Designadas por string, são terminadas pelo carácter ASCII 0x00 (NULL). As contantes e literais deste tipo podem ser utilizados em atribuições, passados como argumentos de funções ( 6) e em impressões ( 8.12). Vectores São sempre homogéneos (contêm valores de um só tipo: inteiro ou real), e.g., quando um vector inclui pelo menos um valor literal real, todo os elementos do vector são reais. Os valores inteiros e reais são considerados vectores unidimensionais, so o escalares interpretados como vectores de dimensão unitária. 1.2 Verificação de tipos Os tipos suportados por cada operador e a operação a realizar são indicados na definição das expressões ( 8). 1.3 Manipulação de nomes As entidades nomeadas ( 2.3) correspondem a constantes ( 4.1), variáveis ( 4.2) e funções ( 6). Usa-se o termo entidade para as designar indiscriminadamente, explicitando-se quando a descrição for válida apenas para um subconjunto. 1.3.1 Espaços de nomes O espaço de nomes global é único: um nome utilizado para designar uma entidade num dado contexto não pode ser utilizado para designar outras (ainda que de natureza diferente). 1.3.2 Validade das variáveis As entidades globais (declaradas fora de qualquer função), existem durante toda a execução do programa. As constantes e variáveis locais a uma função, bem como os seus argumentos formais, existem apenas enquanto ela está activa. 1

1.3.3 Visibilidade dos identificadores Os identificadores são visíveis desde a sua declaração até ao fim do seu alcance: ficheiro (globais) ou função/bloco (locais). A reutilização de um identificador num contexto inferior encobre possíveis declarações em contextos superiores. Em particular, a redeclaração de um identificador numa função encobre o global até ao fim da função. Não é possível definir funções dentro de funções. Existem algumas restrições à declaração de identificadores cujos nomes coincidam com outros já utilizados ( 6.3). 2 Convenções Lexicais Existem seis grupos de elementos lexicais (tokens): estrutura de linha, identificadores, palavras chave, literais, operadores de expressões e delimitadores. Considera-se sempre a maior sequência de caracteres correspondente a um elemento lexical válido. 2.1 Estrutura de linha Um programa está dividido em linhas lógicas e uma instrução não pode ocupar mais de uma linha lógica, excepto se a instrução permitir explicitamente mudanças de linha através, por exemplo, da utilização de blocos. Uma linha lógica pode ser constituída por uma ou mais linhas físicas separadas pelo carácter de continuação. 2.1.1 Linhas físicas A terminação de uma linha física depe da convenção utilizada pelo sistema operativo de suporte utilizado. Assim, em UNIX, o carácter utilizado é o ASCII 0x0A (linefeed, \n). No Macintosh, o carácter utilizado é o ASCII 0x0D (return, \r). Em DOS/Windows, utiliza-se a sequência ASCII 0x0D 0x0A (\r\n). 2.1.2 Carácter de continuação: junção explícita de linhas Duas linhas físicas podem ser juntas numa única linha lógica através da utilização do carácter de continuação: ASCII 0x5C (backslash, \), quando utilizado como último carácter, imediatamente antes da terminação da linha física. Este processo é válido para múltiplas linhas físicas. Por exemplo: if ano > 2006 and ano <= 2010 and dia >= 1 \ and (mes = 1 or mes = 3 or mes = 5 or mes = 7 \ or mes = 8 or mes = 10 or mes = 12 and dia <= 31) \ or (mes = 4 or mes = 6 or mes = 9 or mes = 11 and dia <= 30 )\ or mes = 8 or mes = 10 or mes = 12 and dia <= 31) \ or mes = 2 and (ano = 2008 and dia <= 29 or ano <> 2008 \ and dia <= 28 ) then dia correcto!! dia errado!! Além da utilização descrita, o carácter de continuação pode ser utilizado em cadeias de caracteres literais ( 2.5.3), so ilegal em qualquer outro contexto. Em particular, o carácter de continuação não pode ser utilizado para permitir a continuação de tokens (identificadores, palavras chave, delimitadores, operadores, literais inteiros ou reais), nem comentários explicativos ( 2.2). 2.1.3 Caracteres brancos São considerados caracteres brancos aqueles que, embora servindo para separar os elementos lexicais, não representam nenhum elemento lexical. São considerados caracteres brancos: ASCII 0x20 (espaço, ) e ASCII 0x09 (tabulação, \t). Note-se que os caracteres mencionados acima, apesar de brancos, têm significado especial se aparecerem no início de uma linha lógica ( 2.1.5). Analogamente, os caracteres de mudança de linha ( 2.1.1) também têm significado especial ( 2.1.4 e 2.1.5). 2.1.4 Linhas brancas Uma linha lógica que contenha apenas caracteres brancos ( 2.1.3) e comentários é ignorada. Neste caso não é gerado nenhum elemento lexical nem alterada a indentação. 2

2.1.5 Indentação Tal como mencionado em 2.1.3, os caracteres ASCII 0x20 (espaço, ) e ASCII 0x09 (tabulação, \t) não são considerados brancos no início de uma linha lógica. Neste caso, as suas cadeias determinam o nível de indentação do código. Os caracteres de tabulação são substituídos (da esquerda para a direita) por 1 (um) a 8 (oito) espaços, de tal forma que o número total de caracteres brancos até ao carácter corrente (e incluindo este) seja o múltiplo de 8 seguinte (regra utilizada pelo UNIX). O número total de espaços brancos até ao primeiro carácter não branco determina o nível de indentação da expressão. A indentação não pode continuar na linha física seguinte mediante a utilização de uma junção explícita de linhas. Assim, no máximo, o número de espaços brancos até ao primeiro carácter de continuação determina o nível de indentação, embora as linhas físicas possam ter qualquer comprimento. Embora os diversos níveis de indentação possam ser diferentes, o significado pode ser o mesmo (ver figura 1). (a) OK: bom estilo (b) OK: mau estilo (c) Errado! max(a, b) if a > b then a b max(a, b) if a > b then a b max(a, b) if a > b then a b Figura 1: O código de (a) apresenta melhor legibilidade que o de (b), devido à regularidade da indentação. 2.2 Comentários Os comentários funcionam como separadores de elementos lexicais. Existem dois tipos de comentários. Explicativos Começam com # (se não fizer parte de uma cadeia de caracteres), e acabam no fim da linha física ( 2.1.1). Operacionais Começam com { e terminam com } (se não fizerem parte de cadeias de caracteres). Podem estar aninhados e conter várias linhas físicas ( 2.1.1). Não alteram a indentação ( 2.1.5). 2.3 Identificadores Os identificadores, ou nomes ( 1.3), são iniciados por uma letra (maiúscula ou minúscula) ou um sublinhado (_). O primeiro carácter é seguido por 0 (zero) ou mais letras, dígitos ou _. O número de caracteres de um identificador é ilimitado e dois nomes designam identificadores distintos se houver alteração de maiúscula para minúscula, ou vice-versa, de pelo menos um carácter. 2.4 Palavras chave As seguintes palavras chave estão reservadas, não podo ser utilizadas como identificadores. Estas palavras têm de ser escritas exactamente como indicado. Apesar de definida, goto não é utilizada pela linguagem. not and or if then while do done until break continue return goto real integer string const var init extern 2.5 Literais São notações para valores constantes de alguns tipos da linguagem (não confundir com constantes ( 4.1), i.e., identificadores que designam elementos cujo valor não pode sofrer alterações durante a execução do programa). 3

2.5.1 Inteiros Um literal inteiro é um número não negativo (uma constante inteira pode, contudo, ser negativa: números negativos são construídos pela aplicação do operador menos unário (-) a um literal positivo). Os inteiros ocupam 32 bits. Um literal inteiro em decimal é constituído por uma sequência de 1 (um) ou mais dígitos decimais (de 0 a 9) em que o primeiro dígito não é um 0 (zero), excepto no caso do número 0 (zero). Neste caso, é composto apenas pelo dígito único 0 (zero) (em qualquer base de numeração). Um literal inteiro em octal começa sempre pelo dígito 0 (zero), so seguido de um ou mais dígitos de 0 a 7. Um literal inteiro em hexadecimal começa pela sequência 0x, so seguido de um ou mais dígitos de 0 a 9, de a a f, ou de A a F (elementos da base hexadecimal). Se não for possível representar o literal inteiro em 32 bits, devido a um overflow, deverá ser gerado um erro lexical. 2.5.2 Reais Um literal real é representado em notação científica e ocupa 64 bits. Um literal real inclui sempre um ponto decimal e tem dígitos decimais de um dos lados (podo não ter do outro). Assim, 2. ou 2.0 representam o valor real 2 (dois), enquanto duas décimas podem ser representadas por.2 ou 0.2. Um literal real pode ainda incluir uma parte exponencial contituída pela letra E (ou e) seguida de um inteiro (positivo ou negativo). 2.5.3 Cadeias de caracteres As cadeias de caracteres começam e terminam com plicas ( ). Uma cadeia de caracteres pode conter qualquer número de caracteres, podo estes ser ASCII ou de outras normas (e.g. ISO 8859-1, entre outros), para representação de caracteres acentuados. Dentro de uma cadeia, os caracteres utilizados para iniciar ou terminar comentários (tanto { e }, como #), têm o seu valor normal, não inciando ou terminando qualquer comentário ( 2.2). O carácter \ é utilizado na representação de caracteres especiais de acordo com a seguinte tabela: \ seguido de ASCII 0x0A (newline) ignorado (ver junção de linhas físicas, 2.1.1) \\ \ (backslash) \ (plica) \n ASCII 0x0A (LF, linefeed) \r ASCII 0x0D (CR, carriage return) \t ASCII 0x09 (HT, tab) \b ASCII 0x07 (BEL, bell) \ooo carácter com valor octal dado pelos dígitos ooo \xhh carácter com valor hexadecimal dado pelos dígitos hh (outras sequências) permanecem inalteradas (incluindo o carácter \) A sequência octal, especificada por ooo, pode ter 1, 2, ou 3 dígitos, com valores entre 1 e 377 (máximo representável com 8 bits). Analogamente, a sequência hexadecimal, especificada por hh, pode ter 1 ou 2 dígitos, com valores entre 1 e FF (máximo representável com 8 bits). Tal como nos inteiros ( 2.5.1), não há distinção entre maiúsculas e minúsculas nos dígitos hexadecimais. 2.6 Operadores de expressões São considerados operadores os seguintes elementos lexicais: - + -- ++?!!! @ * / % ** < <= >= > = <> := 2.7 Delimitadores Os elementos lexicais seguintes são considerados delimitadores: [ ] ( ), 4

3 Estrutura 3.1 Gramática A gramática da linguagem pode ser resumida pelas regras abaixo. Considerou-se que os elementos em tipo fixo são literais, que os parênteses curvos agrupam elementos, que elementos alternativos são separados por uma barra vertical, que elementos opcionais estão entre parênteses rectos, que os elementos que se repetem zero ou mais vezes estão entre { e }. Notar que, em reserva e em literal-vector, os parênteses rectos são elementos lexicais da linguagem. ficheiro declaração { declaração } declaração constante variável função constante const identificador {, identificador } := literal {, literal } variável variável-i variável-ni variável-i init identificador := expressão variável-ni var [ tipo ] identificador tipo integer real string função [ tipo ] identificador ( [ argumentos ] ) [ bloco ] argumentos [ tipo ] identificador {, [ tipo ] identificador } literal literal-atómico literal-vector literal-atómico literal-inteiro literal-real cadeia-de-caracteres literal-vector [ literal-atómico {, literal-atómico } ] instrução if expressão then instrução [ instrução ] while expressão do instrução [ instrução ] done do instrução until expressão [ instrução ] done continue [ literal-inteiro ] break [ literal-inteiro ] return bloco expressão reserva reserva [ identificador ] := expressão Foram omitidos da gramática os seguintes elementos: tipo ( 1.1); identificador ( 2.3); literal-inteiro ( 2.5.1); literal-real ( 2.5.2); cadeia-de-caracteres ( 2.5.3); bloco ( 7.2); e expressão (incluindo left-values, i.e., posições de memória para escrita) ( 8). 3.2 Ficheiros Os ficheiros são contituídos por sequências de definições. Estas definições são utilizadas, quer para declarar, quer para reservar espaço para os valores das entidades declaradas. É possível declarar constantes ( 4.1), variáveis ( 4.2) e funções ( 6). Os ficheiros são uniformes, so o principal aquele que contiver a função de arranque do programa, designada por start. 4 Declaração de Variáveis e Constantes 4.1 Constantes Designadas pela palavra chave const, indicam identificadores cujo valor não pode ser modificado. As contantes podem ser de qualquer tipo. Como a inicialização é obrigatória, não é necessária (ou permitida) a especificação do tipo de dados (é inferido do valor). A inicialização pode ser múltipla, so usados múltiplos identificadores e valores iniciais (separados por vírgulas em ambos os casos). Os identificadores e os valores devem ser em igual número e são emparelhados. Numa expressão, caso um identificador designe uma constante escalar o seu valor deverá ser directamente substituído no código. const grosa := 144 const pi := 3.1415926535 const valores := [ 1, 2.4, 3.6, 5 ] const dias, horas, minutos, segundos := 7, 24, 60, 60 const mes, dias := Abril, 30 5

4.2 Variáveis 4.2.1 Variáveis iniciadas Designadas pela palavra chave init, indicam variáveis com valores iniciais. O inicializador é uma sequência de valores separados por vírgulas e delimitados por parênteses rectos (excepto para cadeias de caracteres). Como a inicialização é obrigatória, não é necessária (ou permitida) a especificação do tipo (é inferido do valor). Todos os valores são considerados vectores (os escalares são vectores com um só elemento). Cada instrução inicia uma variável: para iniciar várias variáveis são necessárias outras tantas instruções. A sequência de valores iniciais apenas pode conter literais. init meses := [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ] init dias := [ 365 ] init nome := Gollum Note-se que uma variável denota sempre uma posição de memória, logo dias + 1 = 366 é uma condição verdadeira e equivalente a dias[0] + 1 = 366 (i.e., é possível indexar qualquer variável). A inicialização de uma cadeia de caracteres corresponde à definição de uma variável cujo valor é o ereço inicial da cadeia. O conteúdo da cadeia é constante. 4.2.2 Variáveis não iniciadas Variáveis escalares não iniciadas são designadas com a palavra chave var seguida de um tipo e uma sequência de identificadores separados por vírgulas. var dias, horas var integer minutos, segundos var real comprimento, altura A dimensão das variáveis não iniciadas não escalares (vectores) é indicada entre parênteses rectos. Se a dimensão for omitida, a reserva de memória deve ser efectuada pela operação de reserva de memória ( 7.8). var pilha[20], aux[] var real coordenadas[3] 5 Declarações exteriores A declaração de entidades exteriores só pode ser efectuada fora das funções. A definição de entidades exteriores começa com a palavra chave extern seguida de uma declaração, necessariamente não inicializada, mesmo no caso das constantes ou no caso de inicializações de variáveis noutros módulos (neste caso, pode ser necessária a especificação do tipo). Esta declaração permite a utilização de compilação separada. 6 Funções Uma função permite agrupar um conjunto de instruções num corpo, que é executado com base num conjunto de parâmetros (os argumentos formais) quando é invocada a partir de uma expressão. O programa tem início na função com nome start. 6.1 Declaração As funções que recebam argumentos devem indicá-los no cabeçalho. Funções sem argumentos definem um cabeçalho vazio. A declaração de uma função sem corpo tipifica um identificador exterior ou efectua uma declaração antecipada (para pré-declarar funções que sejam usadas antes da definição, por exemplo, entre duas funções mutuamente recursivas). Caso a declaração tenha corpo, define-se uma nova função. Para o mesmo nome, pode existir apenas uma declaração com corpo. Múltiplas declarações sem corpo com o mesmo nome são possíveis, mas têm de concordar nos tipos do retorno e dos argumentos. Todas as funções devem indicar o tipo de retorno (por omissão, inteiro). Quando invocadas devolvem um valor do tipo indicado. 6

6.2 Invocação Uma função só pode ser invocada através de um identificador que refira uma função previamente declarada. Caso existam argumentos, na invocação da função, o seu identificador é seguido de uma lista de expressões delimitadas por parênteses curvos. A lista de expressões é uma sequência, possivelmente vazia, de expressões separadas por vírgulas. As expressões são avaliadas da direita para a esquerda antes da invocação da função (convenção Cdecl) e cada valor resultante passado por cópia (passagem de argumentos por valor). O número e tipo de parâmetros actuais deve ser igual ao número e tipo dos parâmetros formais da função invocada (i.e., não existem parâmetros opcionais). A ordem dos parâmetros actuais deverá ser a mesma dos argumentos formais. Os parâmetros actuais devem ser colocados na pilha de dados pela ordem inversa da sua declaração e o ereço de retorno no topo da pilha. A função chamadora coloca os argumentos na pilha e é também responsável pela sua remoção, após o retorno da função chamada (Cdecl). Ainda de acordo com esta convenção, a passagem de retorno que não é possível colocar num registo é feita por referência passada como o primeiro argumento (i.e., o chamador reserva o espaço necessário e envia a localização à função invocada). 6.3 Corpo O valor devolvido por uma função, definido através do left-value especial que tem o mesmo nome da função, deve ser do tipo declarado. Podem ser realizadas várias atribuições durante a vida da função, so retornado o valor existente quando a função termina. O nome da variável de retorno é reservado na função correspondente, não podo ser reutilizado como variável local ou nome de um argumento. Os nomes das variáveis (ao corpo da função) não podem ser iguais aos dos argumentos da função. Uma instrução return causa a interrupção imediata da função, assim como a devolução do valor de retorno ao chamador. 6.4 Função principal e execução de programas Um programa inicia-se com a invocação da função start (sem argumentos). Os argumentos com que o programa foi chamado podem ser obtidos através de funções argc() (devolve o número de argumentos); string argv(integer n) (devolve o n-ésimo argumento como um ponteiro para uma cadeia de caracteres) (n > 0); e string envp(integer n) (devolve a n-ésima variável de ambiente como um ponteiro para uma cadeia de caracteres) (n > 0). O valor de retorno desta função é devolvido ao ambiente que invocou o programa. Este valor de retorno segue as seguintes regras (sistema operativo): 0 (zero), execução correu sem erros; 1 (um), argumentos inválidos (em número ou valor); 2 (dois), erro de execução. Os valores superiores a 128 indicam que o programa terminou com um sinal. Em geral, para correcto funcionamento, os programas devem devolver 0 (zero) se a execução foi bem sucedida e um valor diferente de 0 (zero) em caso de erro. A biblioteca de run-time (RTS) contém informação sobre as rotinas de baixo nível disponíveis. 7 Instruções Excepto quando indicado, as instruções são executadas em sequência, so os seus efeitos traduzidos, em geral, pela alteração do valor de variáveis. As instruções são separadas pelas mudanças de uma linha lógica para a seguinte. 7.1 Expressão como instrução Quando uma expressão figurar numa linha lógica, é utilizada como instrução, mesmo que não produza qualquer efeito secundário. A avaliação da expressão é realizada como habitualmente, mas o seu valor é descartado. 7.2 Blocos Um bloco é definido pelas mudanças de indentação que ocorrem nos seus limites: um aumento marca o seu início e uma diminuição o seu fim. Durante o bloco, a indentação é constante. Cada bloco tem uma zona de declarações de constantes e variáveis locais (facultativa), seguida por uma zona (não nula) com instruções. 7

A longevidade das variáveis, bem como a sua visibilidade, é limitada ao bloco em que foram declaradas. As entidades declaradas podem ser directamente utilizadas em sub-blocos ou passadas como argumentos para funções chamadas dentro do bloco. Caso os identificadores usados para definir as constantes e variáveis locais já estejam a ser utilizados para definir outras entidades ao alcance do bloco, o novo identificador passa a referir uma nova entidade definida no bloco até ao que ele termine (a entidade previamente definida continua a existir, mas não pode ser directamente referida pelo seu nome). Esta regra não se aplica à redefinição de variáveis com o mesmo nome da função actual ou dos seus argumentos (ambas são proibidas) ( 6.3). 7.3 Instrução condicional Se o valor da expressão que segue a palavra chave if for diferente de 0 (zero) então a instrução que segue a palavra then é executada. Caso contrário, se existir uma palavra, a instrução correspondente é executada. 7.4 Instruções de iteração O ciclo do-until--done é semelhante ao ciclo do-while da linguagem C. A parte alternativa () é executada se a condição em until nunca for verdadeira (i.e., não é executada se a condição de controlo alguma vez tiver sido verdadeira). O ciclo while-do--done é semelhante ao ciclo while da linguagem C. A parte alternativa () é executada se a condição em while nunca for verdadeira (i.e., não é executada se a condição de controlo alguma vez tiver sido verdadeira). 7.5 Instrução de retorno Indicada pela palavra reservada return, a existir deverá ser a última instrução do bloco em que se insere ( 6.3). 7.6 Instrução de continuação Esta instrução, indicada pela palavra chave continue, reinicia o ciclo interno em que a instrução se encontrar, tal como a instrução continue em C. Quando seguida de um número inteiro n, reinicia o n-ésimo ciclo a contar do actual (n = 1). Esta instrução só pode existir dentro de um ciclo e quando existe deve ser a última do bloco. A especificação de um número maior que o aninhamento dos ciclos é um erro. 7.7 Instrução de terminação Esta instrução, indicada pela palavra chave break, termina a execução do ciclo interno em que a instrução se encontrar, tal como a instrução break em C. Quando seguida de um número inteiro n, termina o n-ésimo ciclo a contar do actual (n = 1). Esta instrução só pode existir dentro de um ciclo e quando existe deve ser a última do bloco. Esta instrução obriga à reavaliação da condição de iteração do ciclo. A especificação de um número maior que o aninhamento dos ciclos é um erro. 7.8 Reserva de memória Esta instrução permite reservar memória na pilha da função actual, conto espaço suficiente para o número de bytes indicados pelo seu argumento inteiro. O tipo de retorno é idêntico ao do left-value utilizado. O identificador da zona de memória deve ser declarado como um vector sem dimensão do tipo apropriado, podo ser um argumento de função. 8 Expressões As expressões são representações algébricas de quantidades (i.e., todas as expressões devolvem um valor). As expressões utilizam operadores algébricos comuns (e.g., soma, subtracção), operadores lógicos (e.g., negação) e relacionais (e.g., maior ou igual). Se a um operador forem passados valores inteiros e reais, os inteiros devem ser promovidos ao valor real correspondente. Analogamente, um inteiro pode ser utilizado onde é esperado um real, devo ser promovido antes da sua utilização. As expressões são sempre avaliadas da esquerda para a direita, indepentemente da associatividade do operador. A precedência dos operadores é a mesma para operadores na mesma secção, so as secções seguintes de menor prioridade que as anteriores. O valor resultante da aplicação da expressão bem como a sua associatividade são indicados para cada operador. 8

A tabela seguinte que resume os operadores, por grupos de precedência decrescente: parênteses ( ) não associativo indexação [ ] da esquerda para a direita posição @ (prefixo) não associativo leitura? (sufixo) não associativo incremento/decremento -- ++ (prefixo ou sufixo) não associativos unária - + (prefixo) não associativos não lógico not (prefixo) não associativo potência ** da direita para a esquerda multiplicativa * / % da esquerda para a direita aditiva + - da esquerda para a direita compação < > <= >= não associativos igualdade = <> da esquerda para a direita e lógico and da esquerda para a direita ou lógico or da esquerda para a direita atribuição := da direita para a esquerda escrita!!! (sufixo) não associativo Operadores com o mesmo nome que em C têm, em geral, o mesmo significado que em C (excepto onde indicado). 8.1 Expressões primárias 8.1.1 Identificadores Identificadores ( 2.3) são expressões desde que tenham sido devidamente declarado: correspondem a nomes de variáveis, constantes, ou funções. Um identificador é o caso mais simples de um left-value, i.e., uma entidade que pode ser utilizada no lado esquerdo (left-value) de uma atribuição. O nome de uma função é um identificador especial dentro da função actual, designando o valor de retorno ( 6.3). 8.1.2 Literais Ver 2.5. 8.1.3 Parênteses curvos Esta expressão tem o valor da expressão sem os parênteses e permite alterar a prioridade dos operadores. Expressões entre parênteses não podem ser utilizadas como left-value ( 8.1.4). 8.1.4 Indexação Esta expressão devolve o valor da posição indicada por um ponteiro: a notação é a expressão do ponteiro, seguida do índice entre parênteses rectos. O resultado é o valor existente na posição de memória base somado com o deslocamento, em quantidades da dimensão do tipo do valor da expressão. O primeiro elemento tem deslocamento 0 (zero). Se a expressão ponteiro for um left-value, então a expressão indexação poderá também ser um left-value. Exemplo: p[0] (acesso à posição apontada por p). 8.1.5 Invocação de funções Ver 6.2. 8.2 Expressões unárias 8.2.1 Expressão de indicação de posição A expressão localização (@) devolve a posição de memória ocupada pelo left-value indicado como argumento. Retorna um valor do tipo do ponteiro apropriado para o objecto em causa. Exemplo: @p indica a posição de memória de p. 9

8.2.2 Leitura A operação de leitura (?) permite atribuir ao left-value indicado um valor inteiro ou real. A operação retorna o valor inteiro 1 (um), se tiver conseguido ler o valor, -1 (menos um) no fim do canal (EOF), e 0 (zero) nos restantes casos. 8.2.3 Identidade A expressão identidade (+) devolve o valor do seu argumento inteiro ou real. 8.2.4 Simétrico A expressão valor simétrico (-) devolve o simétrico do seu argumento inteiro ou real. 8.2.5 Incremento O operador de incremento (++) incrementa em uma unidade o valor do left-value passado como argumento. Pode ser um préincremento (prefixo) ou um pós-incremento (sufixo). Notar que x := x + 1 ou x[0]++ são incrementos de uma unidade ao primeiro valor de x, enquanto x++ é um avanço do ponteiro para o valor seguinte (apenas possível quando x for um ponteiro declarado var x[] ou equivalente). 8.2.6 Decremento O operador de decremento (--) decrementa em uma unidade o valor do left-value passado como argumento. Pode ser um pré-decremento (prefixo) ou um pós-decremento (sufixo). Aplicam-se as disposições enunciadas para o incremento. 8.3 Expressão de potência A operação de potência (**) é apenas aplicável a valores inteiros, devolvo a multiplicação do primeiro argumento por ele próprio tantas vezes quantas o valor do segundo argumento. 8.4 Expressões multiplicativas As operações são aplicáveis a inteiros e reais (excepto onde indicado), devolvo o resultado da respectiva operação algébrica. A divisão (/) é inteira se ambos os operandos o forem. É um erro o denominador ter o valor 0 (zero), tanto no caso da divisão, como no caso do resto da divisão. 8.4.1 Multiplicação A multiplicação (*) corresponde à operação algébrica se os operandos forem inteiros ou reais (há promoção de tipos quando necessário). É possível um uso especial da multiplicação em que o primeiro operando é uma cadeia de caracteres e o segundo um inteiro não negativo (outras combinações de ordem ou sinal são ilegais). Neste caso, a cadeia de caracteres é repetida tantas vezes quantas o valor do inteiro. Um valor 0 (zero) corresponde à cadeia nula. Exemplo: * (i * 2)! imprime uma sequência de caracteres brancos (de comprimento igual ao dobro do valor de i). 8.4.2 Resto de divisão inteira A operação de resto (%) é aplicável a valores inteiros e reais (os operandos reais são truncados). 10

8.5 Expressões aditivas As operações são apenas aplicáveis a valores inteiros e reais, devolvo o resultado da respectiva operação algébrica. Estas operações podem ter ponteiros como operandos, correspondo às operações existentes em C/C++: (i) deslocamentos (um dos operandos deve ser um ponteiro e o outro um inteiro); (ii) diferenças de ponteiros (apenas quando se aplica o operador subtracção (-) a dois ponteiros do mesmo tipo: o resultado é o número de objectos do tipo apontado entre eles). 8.5.1 Somas e cadeias de caracteres Quando um dos elementos da soma é uma cadeia de carateres, quer sob a forma de um literal quer sob a forma de uma constante, o resultado é também uma cadeia de caracteres. Assim, a soma de duas cadeias de caracteres resulta numa cadeia de caracteres que é a concatenação de ambas as sequências. Por outro lado, se um dos elementos for um inteiro ou um real e o outro uma cadeia de caracteres, o inteiro é convertido numa cadeia de caracteres, e o resultado é a concatenação do valor convertido com a cadeia de caracteres. A ordem das cadeias parciais na cadeia final depe da ordem dos operandos da soma. 8.6 Expressões de comparação As operações de comparação (< <= >= >) são aplicáveis a inteiros e reais. Devolvem o valor inteiro 0 (zero) caso a comparação seja falsa e o valor inteiro 1 (um) em caso contrário. 8.7 Expressões de igualdade As operações igual (=) e diferente (<>) são aplicáveis a valores inteiros e reais. Devolvem o valor inteiro 0 (zero) caso a comparação seja falsa e o valor inteiro 1 (um) em caso contrário. 8.8 Expressões de negação lógica A operação (not) é aplicável a valores inteiros e retorna valores inteiros. O valor 0 (zero) representa a condição falsa e o valor 1 (um) a condição verdadeira. 8.9 Expressão de junção lógica A operação (and) é aplicável a valores inteiros, devolvo um valor diferente de zero caso ambos os argumentos sejam diferente de 0 (zero) e o valor 0 (zero) caso contrário. Se o primeiro argumento for 0 (zero), o segundo argumento não deve ser avaliado. 8.10 Expressão de alternativa lógica A operação (or) é aplicável a valores inteiros. Tem o valor inteiro 0 (zero) se ambos os argumentos forem iguais a 0 (zero) e diferente de zero caso contrário. Se o primeiro argumento for diferente de 0 (zero), o segundo argumento não deve ser avaliado. 8.11 Expressão de atribuição O valor da expressão do lado direito do operador (:=) é atribuído à posição indicada pelo lado esquerdo (left-value). O uso de um valor real na atribuição a uma posição inteira é possível e implica uma operação de truncatura. Notar, no exemplo seguinte, que o valor j+5 é colocado em base[j+5], por causa da associatividade do operador. a := base[i] := i := j + 5 8.12 Expressão de escrita A operação de escrita (! ou!!) permite apresentar num canal de saída o valor do seu operando. A versão!! realiza a mesma operação que a versão!, mas provoca uma mudança de linha. O valor devem ser apresentados em decimal para os valores numéricos e em ASCII e ISO 8859-15 para valores do tipo string. 11

9 Exemplos Os exemplos apresentados não são exaustivos, pelo que não ilustram todos os aspectos da linguagem. 9.1 Cálculo do factorial Dois programas para cálculo do factorial. # Factorial recursivo (com função) factorial(n) if n > 1 then factorial := n * factorial(n-1) factorial := n init f = [ 5 ] start() if argc() = 1 then f = atoi(argv(1)) f +! = + factorial(f)!! start := 0 # Factorial iterativo (sem função) start() var f, n, i if argc() = 1 then n := atoi(argv(1)) n := 5 f := i := n while i > 2 do i := i - 1 f := f * i done n +! = + f!! start := 0 9.2 Cálculo de termos da série de Fibonacci Cálculo recursivo de um termo da série de Fibonacci: fibonacci(n) if n = 0 or n = 1 then fibonacci := n fibonacci := fibonacci(n-1) + fibonacci(n-2) start() var n Introduza um número inteiro positivo:! if n? <> 1 or n <= 0 then start := 1 Fibonacci( +n+ ) = +fibonacci(n)!! start := 0 10 Omissões Casos omissos e erros serão corrigidos em futuras versões do manual de referência. 12